{"id":14962126,"url":"https://github.com/tencent/omi","last_synced_at":"2025-05-13T11:10:33.032Z","repository":{"id":32981534,"uuid":"36606437","full_name":"Tencent/omi","owner":"Tencent","description":"Web Components Framework - Web组件框架","archived":false,"fork":false,"pushed_at":"2025-04-28T11:44:36.000Z","size":155234,"stargazers_count":13161,"open_issues_count":72,"forks_count":1251,"subscribers_count":342,"default_branch":"master","last_synced_at":"2025-05-05T20:53:43.333Z","etag":null,"topics":["admin","components","css","custom-elements","dashboard","html","javascript","jsx","omi","reactive-signal","shadow-dom","signal","tailwind","tailwindcss","tsx","typescript","web","web-components","webcomponents"],"latest_commit_sha":null,"homepage":"http://omijs.org","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Tencent.png","metadata":{"files":{"readme":"README.CN.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-05-31T14:24:58.000Z","updated_at":"2025-05-04T02:06:30.000Z","dependencies_parsed_at":"2024-09-02T08:04:53.545Z","dependency_job_id":"8d0c8007-bed7-4445-983d-6cadbeb020df","html_url":"https://github.com/Tencent/omi","commit_stats":{"total_commits":398,"total_committers":17,"mean_commits":23.41176470588235,"dds":"0.18341708542713564","last_synced_commit":"f9a400b5e05a3514ccaf3039cedda6e41e340285"},"previous_names":["alloyteam/nuclear","alloyteam/omi","alloyteam/pui"],"tags_count":170,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tencent%2Fomi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tencent%2Fomi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tencent%2Fomi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tencent%2Fomi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Tencent","download_url":"https://codeload.github.com/Tencent/omi/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253929367,"owners_count":21985802,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["admin","components","css","custom-elements","dashboard","html","javascript","jsx","omi","reactive-signal","shadow-dom","signal","tailwind","tailwindcss","tsx","typescript","web","web-components","webcomponents"],"created_at":"2024-09-24T13:29:13.917Z","updated_at":"2025-05-13T11:10:32.994Z","avatar_url":"https://github.com/Tencent.png","language":"TypeScript","readme":"[English](./README.md) | 简体中文 \n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://omijs.github.io/home/assets/logo.svg\" alt=\"omi\" width=\"100\"/\u003e\u003c/p\u003e\n\u003ch2 align=\"center\"\u003eOmi - Web Components 框架\u003c/h2\u003e\n\n- 📶 信号 **Signal** 驱动的响应式编程，[reactive-signal](https://github.com/Tencent/omi/tree/master/packages/reactive-signal)强力驱动\n- 🧱 [TDesign Web 组件](https://github.com/TDesignOteam/tdesign-web-components) \n- ⚡ **微小的**尺寸，**极速的**性能\n- 💗 [目标 100+ 模板](https://omi.cdn-go.cn/templates/latest/) \u0026 [OMI 模板源码](https://github.com/Tencent/omi/tree/master/packages/omi-templates)\n- 🐲 [OMI Form](https://omi.cdn-go.cn/form/latest/docs/) \u0026 [OMI Form 游乐场](https://omi.cdn-go.cn/form/latest/play/) \u0026 [Lucide Omi 图标](https://github.com/omijs/lucide-omi)\n- 🌐 你要的一切都有: **Web Components**, **JSX**, Function Components, Router, Suspense, Directive, Tailwindcss...\n- 💒 使用 **Constructable Stylesheets** 轻松管理和共享样式\n\n```tsx\nimport { render, signal, tag, Component, h } from 'omi'\n\nconst count = signal(0)\n\nfunction add() {\n  count.value++\n}\n\nfunction sub() {\n  count.value--\n}\n\n@tag('counter-demo')\nexport class CounterDemo extends Component {\n  static css = 'span { color: red; }'\n\n  render() {\n    return (\n      \u003c\u003e\n        \u003cbutton onClick={sub}\u003e-\u003c/button\u003e\n        \u003cspan\u003e{count.value}\u003c/span\u003e\n        \u003cbutton onClick={add}\u003e+\u003c/button\u003e\n      \u003c/\u003e\n    )\n  }\n}\n```\n\n使用该组件:\n\n```tsx\nimport { h } from 'omi'\nimport './counter-demo'\n\nrender(\u003ccounter-demo /\u003e, document.body)\n\n// 或者\nimport { CounterDemo, Other } from './counter-demo'\n// 当需要导入其他东西的时候，防止被 tree shaking\nrender(\u003cCounterDemo /\u003e, document.body)\n\n// 或者\ndocument.body.appendChild(document.createElement('counter-demo'))\n```\n\n## 安装\n\n```bash\nnpm i omi\n```\n\n快速创建 Omi + Vite + TS/JS 项目：\n\n```bash\n$ npx omi-cli init my-app    # 或者创建js项目: npx omi-cli init-js my-app\n$ cd my-app           \n$ npm start           # develop\n$ npm run build       # release\n```\n\n快速创建 Omi + **Router** + **Signal** + **Suspense** + **Tailwindcss** + Vite + TS 项目：\n\n```bash\n$ npx omi-cli init-spa my-app  \n$ cd my-app           \n$ npm start           # develop\n$ npm run build       # release\n```\n\n### 包\n\n- 核心包\n  - [`omi`](https://github.com/Tencent/omi/tree/master/packages/omi) - Omi 框架的实现代码。\n  - [`omi-form`](https://github.com/Tencent/omi/tree/master/packages/omi-form) - 强大易用且跨框架的表单解决方案。\n  - [`lucide-omi`](https://github.com/omijs/lucide-omi) - Lucide 的 Omi 图标集合。\n  - [`omiu`](https://github.com/Tencent/omi/tree/master/packages/omiu) - 希望打造最好的 web 组件。\n  - [`omi-router`](https://github.com/Tencent/omi/tree/master/packages/omi-router) - 创建单页应用。\n  - [`omi-cli`](https://github.com/omijs/cli) - 快速创建 Omi + Vite + TS/JS 项目。\n- 入门套件 (未发布到 npm)\n  - [`omi-elements`](https://github.com/Tencent/omi/tree/master/packages/omi-elements) - 官方推出 Tailwind Omi 套件。\n  - [`omi-starter-spa`](https://github.com/Tencent/omi/tree/master/packages/omi-starter-spa) - 快速创建单页应用(SPA)，内置了 Omi + OmiRouter + Tailwindcss + TypeScript + Vite + Prettier。\n  - [`omi-starter-ts`](https://github.com/Tencent/omi/tree/master/packages/omi-starter-ts) - 基于 Vite + Omi + TypeScript 的模板。\n  - [`omi-starter-tailwind`](https://github.com/Tencent/omi/tree/master/packages/omi-starter-tailwind) - 基于 Vite + Omi + TypeScript + Tailwindcss 的模板。\n  - [`omi-starter-js`](https://github.com/Tencent/omi/tree/master/packages/omi-starter-js) - 基于 Vite + Omi + JavaScript 的模板。\n  - [`omi-vue`](https://github.com/Tencent/omi/tree/master/packages/omi-vue) - Vue SFC + Vite + OMI + OMI-WeUI.\n- 组件\n  - [`omi-weui`](https://github.com/Tencent/omi/tree/master/packages/omi-weui) - Omi 版本的 WeUI。\n  - [`omi-auto-animate`](https://github.com/Tencent/omi/tree/master/packages/omi-auto-animate) - Omi 版本的 @formkit/auto-animate。\n  - [`omi-suspense`](https://github.com/Tencent/omi/tree/master/packages/omi-suspense) - 处理异步依赖。\n- 指令  \n  - [`omi-transition`](https://github.com/Tencent/omi/tree/master/packages/omi-transition) - 提供进入和离开动画。\n  - [`omi-ripple`](https://github.com/Tencent/omi/tree/master/packages/omi-ripple) - 用于为用户界面元素添加涟漪（ripple）效果。当用户与元素交互（例如点击按钮）时，涟漪效果会从交互点开始扩散开来。\n- 综合性例子 (未发布到 npm)\n  - [`snake-game-2tier`](https://github.com/Tencent/omi/tree/master/packages/snake-game-2tier) - 基于 Omi `Signal` class 两层架构的贪吃蛇游戏。\n  - [`snake-game-3tier`](https://github.com/Tencent/omi/tree/master/packages/snake-game-3tier) - 基于 Omi 响应是函数三层架构的贪吃蛇游戏。\n  - [`omi-tutorial`](https://github.com/omijs/tutorial) - Omi 官方教程源代码。\n\n**如果你想帮助项目发展，可以先简单地与同行分享!**\n\n- [Share via Dev.to](\u003chttps://dev.to/new?prefill=---%0Atitle%3A%20Omi%20-%20Web%20Components%20Framework%0A---- %20Home%3A%20%5Bomijs.org%5D(http%3A%2F%2Fomijs.org%2F)%20Github%3A%5Bhttps%3A%2F%2Fgithub.com%2FTencent%2Fomi%5D(https%3A%2F%2Fgithub.com%2FTencent%2Fomi)%0A-%20%F0%9F%93%B6%20**Signal**-driven%20reactive%20programming%0A-%20%F0%9F%8E%89%20%5BTailwind%20Element%20Omi%20UI%20KIT%5D(https%3A%2F%2Fomi.cdn-go.cn%2Felements%2Flatest%2F)%0A-%20%E2%9A%A1%20**Tiny**%20size%2C%20**Fast**%20performance%0A-%20%F0%9F%8C%90%20Everything%20you%20need%3A%20**Web%20Components**%2C%20**JSX**%2C%20Router%2C%20Suspense%2C%20Directive%2C%20Tailwindcss...%0A-%20%F0%9F%92%AF%20Both%20**object**%20oriented%20programming(OOP)%20and%20**data**%20oriented%20programming(DOP)%20are%20supported%0A-%20%F0%9F%92%92%20Harness%20**Constructable%20Stylesheets**%20to%20easily%20manage%20and%20share%20styles\u003e)\n- [Share via Twitter](https://twitter.com/intent/tweet?text=Web%20Components%20Framework%20%F0%9F%8E%89http%3A%2F%2Fomijs.org%2F%0A%0A%20Everything%20you%20need%3A%20Web%20Components%2C%20JSX%2C%20Router%2C%20Suspense%2C%20Directive%2C%20Tailwindcss...%20%0A%0A%20Tailwind%20Element%20Omi%20UI%20KIT%3E%20%F0%9F%92%AFhttps%3A%2F%2Fomi.cdn-go.cn%2Felements%2Flatest%2F)\n- [Share via Facebook](https://www.facebook.com/sharer/sharer.php?u=http%3A//omijs.org)\n- [Share via LinkedIn](http://www.linkedin.com/shareArticle?url=http%3A%2F%2Fomijs.org%2F)\n- [Share via Pinterest](https://www.pinterest.com/pin/create/button?url=http://omijs.org/\u0026media=https://repository-images.githubusercontent.com/36606437/66abfcfb-096b-4c9d-a290-77165213e605\u0026description=Omi-Web%20Componnets%20Framework)\n- [Share via Reddit](https://reddit.com/submit?url=http://omijs.org/\u0026title=web%20components%20framework)\n- [Share via StumbleUpon](https://www.stumbleupon.com/submit?url=http://omijs.org/\u0026title=web%20components%20framework)\n- [Share via Vkontakte](https://vk.com/share.php?url=http://omijs.org/)\n- [Share via Weibo](https://service.weibo.com/share/share.php?url=https://omijs.org/\u0026title=web%20components%20framework)\n- [Share via Hackernews](https://news.ycombinator.com/submitlink?u=http://omijs.org/\u0026t=web%20components%20framework)\n\n多谢！\n\n## 使用\n\n### TodoApp 使用响应式函数\n\n\u003e 数据驱动编程\n\n在数据驱动编程中，我们将重点放在数据本身和对数据的操作上，而不是数据所在的对象或数据结构。这种编程范式强调的是数据的变化和流动，以及如何响应这些变化。基于响应式函数的 TodoApp 就是一个很好的例子，它使用了响应式编程的概念，当数据（即待办事项列表）发生变化时，UI 会自动更新以反映这些变化。\n\n\n```tsx\nimport { render, signal, computed, tag, Component, h } from 'omi'\n\nconst todos = signal([\n  { text: 'Learn OMI', completed: true },\n  { text: 'Learn Web Components', completed: false },\n  { text: 'Learn JSX', completed: false },\n  { text: 'Learn Signal', completed: false }\n])\n\nconst completedCount = computed(() =\u003e {\n  return todos.value.filter(todo =\u003e todo.completed).length\n})\n\nconst newItem = signal('')\n\nfunction addTodo() {\n  // api a，不会重新创建数组\n  todos.value.push({ text: newItem.value, completed: false })\n  todos.update() // 非值类型的数据更新需要手动调用 update 方法\n\n  // api b, 和上面的 api a 效果一样，但是会创建新的数组\n  // todos.value = [...todos.value, { text: newItem.value, completed: false }]\n\n  newItem.value = '' // 值类型的数据更新需会自动 update\n}\n\nfunction removeTodo(index: number) {\n  todos.value.splice(index, 1)\n  todos.update() // 非值类型的数据更新需要手动调用 update 方法\n}\n\n@tag('todo-list')\nclass TodoList extends Component {\n  onInput = (event: Event) =\u003e {\n    const target = event.target as HTMLInputElement\n    newItem.value = target.value\n  }\n\n  render() {\n    return (\n      \u003c\u003e\n        \u003cinput type=\"text\" value={newItem.value} onInput={this.onInput} /\u003e\n        \u003cbutton onClick={addTodo}\u003eAdd\u003c/button\u003e\n        \u003cul\u003e\n          {todos.value.map((todo, index) =\u003e {\n            return (\n              \u003cli\u003e\n                \u003clabel\u003e\n                  \u003cinput\n                    type=\"checkbox\"\n                    checked={todo.completed}\n                    onInput={() =\u003e {\n                      todo.completed = !todo.completed\n                      todos.update()\n                    }}\n                  /\u003e\n                  {todo.completed ? \u003cs\u003e{todo.text}\u003c/s\u003e : todo.text}\n                \u003c/label\u003e\n                {' '}\n                \u003cbutton onClick={() =\u003e removeTodo(index)}\u003e❌\u003c/button\u003e\n              \u003c/li\u003e\n            )\n          })}\n        \u003c/ul\u003e\n        \u003cp\u003eCompleted count: {completedCount.value}\u003c/p\u003e\n      \u003c/\u003e\n    )\n  }\n}\n\nrender(\u003ctodo-list /\u003e, document.body)\n```\n\n\n## 自动导入 h\n\nvite.config.js:\n\n```tsx\nimport { defineConfig } from 'vite'\n\nexport default defineConfig({\n  esbuild: {\n    jsxInject: \"import { h } from 'omi'\",\n    jsxFactory: \"h\",\n    jsxFragment: \"h.f\"\n  }\n})\n```\n\n你可以在构建时候注入代码，这样就不用手动导出 `h`。\n\n## 定义跨框架组件\n\n在 Vue 中使用 Omi component 例子如下:\n\n![](./assets/omi-vue.gif)\n\nmy-counter.tsx:\n\n```tsx\nimport { tag, Component, h, bind } from 'omi'\n\n@tag('my-counter')\nclass MyCounter extends Component\u003c{ count: number }\u003e {\n  static props = {\n    count: {\n      type: Number,\n      default: 0,\n      changed(newValue, oldValue) {\n        this.setState({ count: newValue })\n      }\n    }\n  }\n\n  state = {\n    count: 1\n  }\n\n  @bind\n  sub() {\n    this.setState({ count: this.state.count - 1 })\n    this.fire('change', this.state.count)\n  }\n\n  @bind\n  add() {\n    this.setState({ count: this.state.count + 1 })\n    this.fire('change', this.state.count)\n  }\n\n  render() {\n    return (\n      \u003c\u003e\n        \u003cbutton onClick={this.sub}\u003e-\u003c/button\u003e\n        \u003cspan\u003e{this.state.count}\u003c/span\u003e\n        \u003cbutton onClick={this.add}\u003e+\u003c/button\u003e\n      \u003c/\u003e\n    )\n  }\n}\n```\n\n### 在 Vue3 中使用\n\n```vue\n\u003cscript setup\u003e\nimport { ref } from 'vue'\n// 导入 omi 组件\nimport './my-counter'\n\ndefineProps({\n  msg: String,\n})\n\nconst count = ref(0)\n\nconst change = (e) =\u003e {\n  count.value = e.detail\n}\n\n\u003c/script\u003e\n\n\u003ctemplate\u003e\n  \u003ch1\u003e{{ msg }}\u003c/h1\u003e\n\n  \u003cmy-counter @change=\"change\" :count=\"count\" /\u003e\n  \u003cp\u003e\n    【Omi】 \n  \u003c/p\u003e\n\n  \u003cdiv class=\"card\"\u003e\n    \u003cbutton type=\"button\" @click=\"count++\"\u003ecount is {{ count }}\u003c/button\u003e\n    \u003cp\u003e\n     【Vue】 \n    \u003c/p\u003e\n  \u003c/div\u003e\n\n\u003c/template\u003e\n```\n\n如果在 omi 组件中使用:\n\n```ts\nthis.fire('count-change', this.state.count)\n```\n\n在 vue 中使用组件监听事件如下:\n\n```html\n\u003cmy-counter @count-change=\"change\" :count=\"count\" /\u003e\n```\n\n\n### 在 React 中使用\n\n```tsx\nimport { useState, useRef, useEffect } from 'react'\nimport useEventListener from '@use-it/event-listener'\nimport './my-counter'\n\nfunction App() {\n  const [count, setCount] = useState(100)\n  const myCounterRef = useRef(null)\n\n  useEffect(() =\u003e {\n    const counter = myCounterRef.current\n    if (counter) {\n      const handleChange = (evt) =\u003e {\n        setCount(evt.detail)\n      }\n      counter.addEventListener('change', handleChange)\n      return () =\u003e {\n        counter.removeEventListener('change', handleChange)\n      }\n    }\n  }, [])\n\n  return (\n    \u003c\u003e\n      \u003ch1\u003eOmi + React\u003c/h1\u003e\n      \u003cmy-counter count={count} ref={myCounterRef}\u003e\u003c/my-counter\u003e\n      \u003cdiv className=\"card\"\u003e\n        \u003cbutton onClick={() =\u003e setCount((count) =\u003e count + 1)}\u003e\n          count is {count}\n        \u003c/button\u003e\n      \u003c/div\u003e\n    \u003c/\u003e\n  )\n}\n\nexport default App\n```\n\n## 贡献者\n\n\u003ca href=\"https://github.com/Tencent/omi/graphs/contributors\"\u003e\n  \u003cimg src=\"./assets/contributors.png\" /\u003e\n\u003c/a\u003e\n\n## License\n\nMIT © Tencent\n\n\n\n  \u003c!-- - [`tdesign-omi`](https://github.com/omijs/tdesign) - `[进行中...]`基于 TDesign 和 Omi 的跨框架 组件 集合。 [点击这里预览一下](https://omijs.github.io/tdesign/) --\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftencent%2Fomi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftencent%2Fomi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftencent%2Fomi/lists"}