29 Star 136 Fork 0

腾讯开源 / omi

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

English | 简体中文

omi

Omi - Web Components 框架

  • 📶 信号 Signal 驱动的响应式编程,reactive-signal强力驱动
  • 微小的尺寸,极速的性能
  • 💗 目标 100+ 模板 & OMI 模板源码
  • 🐲 OMI Form & OMI Form 游乐场 & Lucide Omi 图标
  • 🌐 你要的一切都有: Web Components, JSX, Function Components, Router, Suspense, Directive, Tailwindcss...
  • 💯 面向对象编程(OOP) 和 数据驱动编程(DOP) 两种范式都支持
  • 💒 使用 Constructable Stylesheets 轻松管理和共享样式
import { render, signal, tag, Component, h } from 'omi'

const count = signal(0)

function add() {
  count.value++
}

function sub() {
  count.value--
}

@tag('counter-demo')
export class CounterDemo extends Component {
  static css = 'span { color: red; }'

  render() {
    return (
      <>
        <button onClick={sub}>-</button>
        <span>{count.value}</span>
        <button onClick={add}>+</button>
      </>
    )
  }
}

使用该组件:

import { h } from 'omi'
import './counter-demo'

render(<counter-demo />, document.body)

// 或者
import { CounterDemo, Other } from './counter-demo'
// 当需要导入其他东西的时候,防止被 tree shaking
render(<CounterDemo />, document.body)

// 或者
document.body.appendChild(document.createElement('counter-demo'))

安装

npm i omi

快速创建 Omi + Vite + TS/JS 项目:

$ npx omi-cli init my-app    # 或者创建js项目: npx omi-cli init-js my-app
$ cd my-app           
$ npm start           # develop
$ npm run build       # release

快速创建 Omi + Router + Signal + Suspense + Tailwindcss + Vite + TS 项目:

$ npx omi-cli init-spa my-app  
$ cd my-app           
$ npm start           # develop
$ npm run build       # release

  • 核心包
    • omi - Omi 框架的实现代码。
    • omi-form - 强大易用且跨框架的表单解决方案。
    • lucide-omi - Lucide 的 Omi 图标集合。
    • omiu - 希望打造最好的 web 组件。
    • omi-router - 创建单页应用。
    • omi-cli - 快速创建 Omi + Vite + TS/JS 项目。
  • 入门套件 (未发布到 npm)
    • omi-elements - 官方推出 Tailwind Omi 套件。
    • omi-starter-spa - 快速创建单页应用(SPA),内置了 Omi + OmiRouter + Tailwindcss + TypeScript + Vite + Prettier。
    • omi-starter-ts - 基于 Vite + Omi + TypeScript 的模板。
    • omi-starter-tailwind - 基于 Vite + Omi + TypeScript + Tailwindcss 的模板。
    • omi-starter-js - 基于 Vite + Omi + JavaScript 的模板。
    • omi-vue - Vue SFC + Vite + OMI + OMI-WeUI.
  • 组件
  • 指令
    • omi-transition - 提供进入和离开动画。
    • omi-ripple - 用于为用户界面元素添加涟漪(ripple)效果。当用户与元素交互(例如点击按钮)时,涟漪效果会从交互点开始扩散开来。
  • 综合性例子 (未发布到 npm)

如果你想帮助项目发展,可以先简单地与同行分享!

多谢!

使用

TodoApp 使用响应式函数

数据驱动编程

在数据驱动编程中,我们将重点放在数据本身和对数据的操作上,而不是数据所在的对象或数据结构。这种编程范式强调的是数据的变化和流动,以及如何响应这些变化。基于响应式函数的 TodoApp 就是一个很好的例子,它使用了响应式编程的概念,当数据(即待办事项列表)发生变化时,UI 会自动更新以反映这些变化。

import { render, signal, computed, tag, Component, h } from 'omi'

const todos = signal([
  { text: 'Learn OMI', completed: true },
  { text: 'Learn Web Components', completed: false },
  { text: 'Learn JSX', completed: false },
  { text: 'Learn Signal', completed: false }
])

const completedCount = computed(() => {
  return todos.value.filter(todo => todo.completed).length
})

const newItem = signal('')

function addTodo() {
  // api a,不会重新创建数组
  todos.value.push({ text: newItem.value, completed: false })
  todos.update() // 非值类型的数据更新需要手动调用 update 方法

  // api b, 和上面的 api a 效果一样,但是会创建新的数组
  // todos.value = [...todos.value, { text: newItem.value, completed: false }]

  newItem.value = '' // 值类型的数据更新需会自动 update
}

function removeTodo(index: number) {
  todos.value.splice(index, 1)
  todos.update() // 非值类型的数据更新需要手动调用 update 方法
}

@tag('todo-list')
class TodoList extends Component {
  onInput = (event: Event) => {
    const target = event.target as HTMLInputElement
    newItem.value = target.value
  }

  render() {
    return (
      <>
        <input type="text" value={newItem.value} onInput={this.onInput} />
        <button onClick={addTodo}>Add</button>
        <ul>
          {todos.value.map((todo, index) => {
            return (
              <li>
                <label>
                  <input
                    type="checkbox"
                    checked={todo.completed}
                    onInput={() => {
                      todo.completed = !todo.completed
                      todos.update()
                    }}
                  />
                  {todo.completed ? <s>{todo.text}</s> : todo.text}
                </label>
                {' '}
                <button onClick={() => removeTodo(index)}></button>
              </li>
            )
          })}
        </ul>
        <p>Completed count: {completedCount.value}</p>
      </>
    )
  }
}

render(<todo-list />, document.body)

TodoApp 使用信号类 Signal

面向对象编程

在面向对象编程中,我们将重点放在对象上,对象包含了数据和操作数据的方法。这种编程范式强调的是对象之间的交互和协作,以及如何通过对象的封装、继承和多态性来组织和管理代码。基于响应式函数的 TodoApp 也可以使用面向对象的方式来实现,例如,我们可以创建一个 TodoList 类,这个类包含了待办事项列表的数据和操作这些数据的方法,以及一个 update 方法来更新 UI。

import { render, Signal, tag, Component, h, computed } from 'omi'

type Todo = { text: string, completed: boolean }

class TodoApp extends Signal<{ todos: Todo[], filter: string, newItem: string }> {
  completedCount: ReturnType<typeof computed>

  constructor(todos: Todo[] = []) {
    super({ todos, filter: 'all', newItem: '' })
    this.completedCount = computed(() => this.value.todos.filter(todo => todo.completed).length)
  }

  addTodo = () => {
    // api a
    this.value.todos.push({ text: this.value.newItem, completed: false })
    this.value.newItem = ''
    this.update()

    // api b, same as api a
    // this.update((value) => {
    //   value.todos.push({ text: value.newItem, completed: false })
    //   value.newItem = ''
    // })
  }

  toggleTodo = (index: number) => {
    const todo = this.value.todos[index]
    todo.completed = !todo.completed
    this.update()
  }

  removeTodo = (index: number) => {
    this.value.todos.splice(index, 1)
    this.update()
  }
}

const todoApp = new TodoApp([
  { text: 'Learn OMI', completed: true },
  { text: 'Learn Web Components', completed: false },
  { text: 'Learn JSX', completed: false },
  { text: 'Learn Signal', completed: false }
])

@tag('todo-list')
class TodoList extends Component {
  onInput = (event: Event) => {
    const target = event.target as HTMLInputElement
    todoApp.value.newItem = target.value
  }

  render() {
    const { todos } = todoApp.value
    const { completedCount, toggleTodo, addTodo, removeTodo } = todoApp
    return (
      <>
        <input type="text" value={todoApp.value.newItem} onInput={this.onInput} />
        <button onClick={addTodo}>Add</button>
        <ul>
          {todos.map((todo, index) => {
            return (
              <li>
                <label>
                  <input
                    type="checkbox"
                    checked={todo.completed}
                    onInput={() => toggleTodo(index)}
                  />
                  {todo.completed ? <s>{todo.text}</s> : todo.text}
                </label>
                {' '}
                <button onClick={() => removeTodo(index)}></button>
              </li>
            )
          })}
        </ul>
        <p>Completed count: {completedCount.value}</p>
      </>
    )
  }
}

render(<todo-list />, document.body)

这里不讨论哪种方式(DOP,OOP)的好坏,使用 omi 两种方式都可以任意选择。

自动导入 h

vite.config.js:

import { defineConfig } from 'vite'

export default defineConfig({
  esbuild: {
    jsxInject: "import { h } from 'omi'",
    jsxFactory: "h",
    jsxFragment: "h.f"
  }
})

你可以在构建时候注入代码,这样就不用手动导出 h

定义跨框架组件

在 Vue 中使用 Omi component 例子如下:

my-counter.tsx:

import { tag, Component, h, bind } from 'omi'

@tag('my-counter')
class MyCounter extends Component {
  static props = {
    count: {
      type: Number,
      default: 0,
      changed(newValue, oldValue) {
        this.state.count = newValue
        this.update()
      }
    }
  }

  state = {
    count: null
  }

  install() {
    this.state.count = this.props.count
  }

  @bind
  sub() {
    this.state.count--
    this.update()
    this.fire('change', this.state.count)
  }

  @bind
  add() {
    this.state.count++
    this.update()
    this.fire('change', this.state.count)
  }

  render() {
    return (
      <>
        <button onClick={this.sub}>-</button>
        <span>{this.state.count}</span>
        <button onClick={this.add}>+</button>
      </>
    )
  }
}

在 Vue3 中使用

<script setup>
import { ref } from 'vue'
// 导入 omi 组件
import './my-counter'

defineProps({
  msg: String,
})

const count = ref(0)

const change = (e) => {
  count.value = e.detail
}

</script>

<template>
  <h1>{{ msg }}</h1>

  <my-counter @change="change" :count="count" />
  <p>
    【Omi】 
  </p>

  <div class="card">
    <button type="button" @click="count++">count is {{ count }}</button>
    <p>
     【Vue】 
    </p>
  </div>

</template>

如果在 omi 组件中使用:

this.fire('count-change', this.state.count)

在 vue 中使用组件监听事件如下:

<my-counter @count-change="change" :count="count" />

在 React 中使用

import { useState, useRef, useEffect } from 'react'
import useEventListener from '@use-it/event-listener'
import './my-counter'

function App() {
  const [count, setCount] = useState(100)
  const myCounterRef = useRef(null)

  useEffect(() => {
    const counter = myCounterRef.current
    if (counter) {
      const handleChange = (evt) => {
        setCount(evt.detail)
      }
      counter.addEventListener('change', handleChange)
      return () => {
        counter.removeEventListener('change', handleChange)
      }
    }
  }, [])

  return (
    <>
      <h1>Omi + React</h1>
      <my-counter count={count} ref={myCounterRef}></my-counter>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
      </div>
    </>
  )
}

export default App

贡献者

License

MIT © Tencent

English | [简体中文](./README.CN.md) <p align="center"><img src="https://omijs.github.io/home/assets/logo.svg" alt="omi" width="100"/></p> <h2 align="center">Omi - Web Components Framework</h2> - 📶 **Signal**-driven reactive programming by [reactive-signal](https://github.com/Tencent/omi/tree/master/packages/reactive-signal) - 💗 [100+ OMI Templates](https://omi.cdn-go.cn/templates/latest/) & [OMI Templates Source Code](https://github.com/Tencent/omi/tree/master/packages/omi-templates) - 🐲 [OMI Form](https://omi.cdn-go.cn/form/latest/docs/) & [OMI Form Playground](https://omi.cdn-go.cn/form/latest/play/) & [Lucide Omi Icons](https://github.com/omijs/lucide-omi) - ⚡ **Tiny** size, **Fast** performance - 🌐 Everything you need: **Web Components**, **JSX**, Function Components, Router, Suspense, Directive, Tailwindcss... - 💯 Both **object** oriented programming(OOP) and **data** oriented programming(DOP) are supported - 💒 Harness **Constructable Stylesheets** to easily manage and share styles ```tsx import { render, signal, tag, Component, h } from 'omi' const count = signal(0) function add() { count.value++ } function sub() { count.value-- } @tag('counter-demo') export class CounterDemo extends Component { static css = 'span { color: red; }' render() { return ( <> <button onClick={sub}>-</button> <span>{count.value}</span> <button onClick={add}>+</button> </> ) } } ``` Use this component: ```tsx import { h } from 'omi' import './counter-demo' render(<counter-demo />, document.body) // or import { CounterDemo, Other } from './counter-demo' // Prevent tree Shaking when importing other things render(<CounterDemo />, document.body) // or document.body.appendChild(document.createElement('counter-demo')) ``` ## Install ```bash npm i omi ``` To quickly create an Omi + Vite + TS/JS project: ```bash $ npx omi-cli init my-app # or create js project by: npx omi-cli init-js my-app $ cd my-app $ npm start # develop $ npm run build # release ``` To quickly create an Omi + **Router** + **Signal** + **Suspense** + **Tailwindcss** + Vite + TS project: ```bash $ npx omi-cli init-spa my-app $ cd my-app $ npm start # develop $ npm run build # release ``` ### Packages - Core packages - [`omi`](https://github.com/Tencent/omi/tree/master/packages/omi) - Implementation of omi framework. - [`omi-form`](https://github.com/Tencent/omi/tree/master/packages/omi-form) - Powerful, simple and cross frameworks form solution. - [`lucide-omi`](https://github.com/omijs/lucide-omi) - Lucide icon collection for omi. - [`omiu`](https://github.com/Tencent/omi/tree/master/packages/omiu) - Hope to create the best web components. For example, the powerful [vchart](https://visactor.io/vchart) and [vtable](https://visactor.io/vtable) - [`omi-router`](https://github.com/Tencent/omi/tree/master/packages/omi-router) - Create SPA of omi framework. - [`omi-cli`](https://github.com/omijs/cli) - To quickly create an Omi + Vite + TS/JS project. - Starter kits (not published to npm) - [`omi-elements`](https://github.com/Tencent/omi/tree/master/packages/omi-elements) - Tailwind Element Omi UI KIT. - [`omi-starter-spa`](https://github.com/Tencent/omi/tree/master/packages/omi-starter-spa) - A starter repo for building single page app using Omi + OmiRouter + Tailwindcss + TypeScript + Vite + Prettier. - [`omi-starter-ts`](https://github.com/Tencent/omi/tree/master/packages/omi-starter-ts) - A starter repo for building web app or reusable components using Omi in TypeScript base on Vite. - [`omi-starter-tailwind`](https://github.com/Tencent/omi/tree/master/packages/omi-starter-tailwind) - A starter repo for building web app or reusable components using Omi + Tailwindcss + TypeScript + Vite. - [`omi-starter-js`](https://github.com/Tencent/omi/tree/master/packages/omi-starter-js) - A starter repo for building web app or reusable components using Omi in JavaScript base on Vite. - [`omi-vue`](https://github.com/Tencent/omi/tree/master/packages/omi-vue) - Vue SFC + Vite + OMI + OMI-WeUI. - Components - [`omi-weui`](https://github.com/Tencent/omi/tree/master/packages/omi-weui) - WeUI Components of omi. - [`omi-auto-animate`](https://github.com/Tencent/omi/tree/master/packages/omi-auto-animate) - Omi version of @formkit/auto-animate. - [`omi-suspense`](https://github.com/Tencent/omi/tree/master/packages/omi-suspense) - Handling asynchronous dependencies. - Directives - [`omi-transition`](https://github.com/Tencent/omi/tree/master/packages/omi-transition) - Applying animations when an component is entering and leaving the DOM. - [`omi-ripple`](https://github.com/Tencent/omi/tree/master/packages/omi-ripple) - A lightweight component for adding ripple effects to user interface elements. - Examples (not published to npm) - [`snake-game-2tier`](https://github.com/Tencent/omi/tree/master/packages/snake-game-2tier) - SNake Game with `Signal` class - [`snake-game-3tier`](https://github.com/Tencent/omi/tree/master/packages/snake-game-3tier) - SNake Game with reactivity functions - [`omi-tutorial`](https://github.com/omijs/tutorial) - Source code of omi tutorial. **If you want to help the project grow, start by simply sharing it with your peers!** - [Share via Dev.to](<https://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>) - [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) - [Share via Facebook](https://www.facebook.com/sharer/sharer.php?u=http%3A//omijs.org) - [Share via LinkedIn](http://www.linkedin.com/shareArticle?url=http%3A%2F%2Fomijs.org%2F) - [Share via Pinterest](https://www.pinterest.com/pin/create/button?url=http://omijs.org/&media=https://repository-images.githubusercontent.com/36606437/66abfcfb-096b-4c9d-a290-77165213e605&description=Omi-Web%20Componnets%20Framework) - [Share via Reddit](https://reddit.com/submit?url=http://omijs.org/&title=web%20components%20framework) - [Share via StumbleUpon](https://www.stumbleupon.com/submit?url=http://omijs.org/&title=web%20components%20framework) - [Share via Vkontakte](https://vk.com/share.php?url=http://omijs.org/) - [Share via Weibo](https://service.weibo.com/share/share.php?url=https://omijs.org/&title=web%20components%20framework) - [Share via Hackernews](https://news.ycombinator.com/submitlink?u=http://omijs.org/&t=web%20components%20framework) Thank you! ## Usage ### TodoApp with reactivity functions > Data oriented programming In data-oriented programming, the focus is on the data itself and the operations on the data, rather than the objects or data structures that hold the data. This programming paradigm emphasizes the change and flow of data, and how to respond to these changes. The TodoApp with reactivity functions is a good example of this, using the concepts of reactive programming, where the UI automatically updates to reflect changes in the data (i.e., the to-do list). ```tsx import { render, signal, computed, tag, Component, h } from 'omi' const todos = signal([ { text: 'Learn OMI', completed: true }, { text: 'Learn Web Components', completed: false }, { text: 'Learn JSX', completed: false }, { text: 'Learn Signal', completed: false } ]) const completedCount = computed(() => { return todos.value.filter(todo => todo.completed).length }) const newItem = signal('') function addTodo() { // api a todos.value.push({ text: newItem.value, completed: false }) todos.update() // Trigger UI auto update // api b, same as api a // todos.value = [...todos.value, { text: newItem.value, completed: false }] newItem.value = '' // Changing the value type can automatically update the UI } function removeTodo(index: number) { todos.value.splice(index, 1) todos.update() // Trigger UI auto update } @tag('todo-list') class TodoList extends Component { onInput = (event: Event) => { const target = event.target as HTMLInputElement newItem.value = target.value } render() { return ( <> <input type="text" value={newItem.value} onInput={this.onInput} /> <button onClick={addTodo}>Add</button> <ul> {todos.value.map((todo, index) => { return ( <li> <label> <input type="checkbox" checked={todo.completed} onInput={() => { todo.completed = !todo.completed todos.update() // Trigger UI auto update }} /> {todo.completed ? <s>{todo.text}</s> : todo.text} </label> {' '} <button onClick={() => removeTodo(index)}>❌</button> </li> ) })} </ul> <p>Completed count: {completedCount.value}</p> </> ) } } render(<todo-list />, document.body) ``` ### TodoApp with Signal Class > Object oriented programming In object-oriented programming, the focus is on the objects, which contain both data and methods to operate on the data. This programming paradigm emphasizes the interaction and cooperation between objects, and how to organize and manage code through object encapsulation, inheritance, and polymorphism. The TodoApp with reactivity functions can also be implemented in an object-oriented way, for example, by creating a TodoList class that contains the data of the to-do list and methods to operate on this data, as well as a `update` method to update the UI. ```tsx import { render, Signal, tag, Component, h, computed } from 'omi' type Todo = { text: string, completed: boolean } class TodoApp extends Signal<{ todos: Todo[], filter: string, newItem: string }> { completedCount: ReturnType<typeof computed> constructor(todos: Todo[] = []) { super({ todos, filter: 'all', newItem: '' }) this.completedCount = computed(() => this.value.todos.filter(todo => todo.completed).length) } addTodo = () => { // api a this.value.todos.push({ text: this.value.newItem, completed: false }) this.value.newItem = '' this.update() // api b, same as api a // this.update((value) => { // value.todos.push({ text: value.newItem, completed: false }) // value.newItem = '' // }) } toggleTodo = (index: number) => { const todo = this.value.todos[index] todo.completed = !todo.completed this.update() } removeTodo = (index: number) => { this.value.todos.splice(index, 1) this.update() } } const todoApp = new TodoApp([ { text: 'Learn OMI', completed: true }, { text: 'Learn Web Components', completed: false }, { text: 'Learn JSX', completed: false }, { text: 'Learn Signal', completed: false } ]) @tag('todo-list') class TodoList extends Component { onInput = (event: Event) => { const target = event.target as HTMLInputElement todoApp.value.newItem = target.value } render() { const { todos } = todoApp.value const { completedCount, toggleTodo, addTodo, removeTodo } = todoApp return ( <> <input type="text" value={todoApp.value.newItem} onInput={this.onInput} /> <button onClick={addTodo}>Add</button> <ul> {todos.map((todo, index) => { return ( <li> <label> <input type="checkbox" checked={todo.completed} onInput={() => toggleTodo(index)} /> {todo.completed ? <s>{todo.text}</s> : todo.text} </label> {' '} <button onClick={() => removeTodo(index)}>❌</button> </li> ) })} </ul> <p>Completed count: {completedCount.value}</p> </> ) } } render(<todo-list />, document.body) ``` We won't discuss which method is good or bad here. You can choose either method using omi. ## Auto Import h vite.config.js: ```tsx import { defineConfig } from 'vite' export default defineConfig({ esbuild: { jsxInject: "import { h } from 'omi'", jsxFactory: "h", jsxFragment: "h.f" } }) ``` You can inject code during construction, so you don't have to manually export `h`. <!-- ## With Twind ```tsx import { Component, define, h } from 'omi' import install from '@twind/with-web-components' import { defineConfig } from '@twind/core' import presetAutoprefix from '@twind/preset-autoprefix' import presetTailwind from '@twind/preset-tailwind' const withTwind = install(defineConfig({ presets: [presetAutoprefix(), presetTailwind()], })) define('my-app', class extends withTwind(Component) { render() { return <h1 class="text-3xl font-bold underline">Hello world!</h1> } }) ``` --> ## Define Cross Framework Component The case of using Omi component in Vue is as follows: ![](./assets/omi-vue.gif) my-counter.tsx: ```tsx import { tag, Component, h, bind } from 'omi' @tag('my-counter') class MyCounter extends Component { static props = { count: { type: Number, default: 0, changed(newValue, oldValue) { this.state.count = newValue this.update() } } } state = { count: null } install() { this.state.count = this.props.count } @bind sub() { this.state.count-- this.update() this.fire('change', this.state.count) } @bind add() { this.state.count++ this.update() this.fire('change', this.state.count) } render() { return ( <> <button onClick={this.sub}>-</button> <span>{this.state.count}</span> <button onClick={this.add}>+</button> </> ) } } ``` ### Using in Vue3 ```vue <script setup> import { ref } from 'vue' // import omi component import './my-counter' defineProps({ msg: String, }) const count = ref(0) const change = (e) => { count.value = e.detail } </script> <template> <h1>{{ msg }}</h1> <my-counter @change="change" :count="count" /> <p> 【Omi】 </p> <div class="card"> <button type="button" @click="count++">count is {{ count }}</button> <p> 【Vue】 </p> </div> </template> ``` If you `fire` the `count-change` in an Omi component: ```ts this.fire('count-change', this.state.count) ``` To use the component and listen for events in Vue: ```html <my-counter @count-change="change" :count="count" /> ``` ### Using in React ```tsx import { useState, useRef, useEffect } from 'react' import useEventListener from '@use-it/event-listener' import './my-counter' function App() { const [count, setCount] = useState(100) const myCounterRef = useRef(null) useEffect(() => { const counter = myCounterRef.current if (counter) { const handleChange = (evt) => { setCount(evt.detail) } counter.addEventListener('change', handleChange) return () => { counter.removeEventListener('change', handleChange) } } }, []) return ( <> <h1>Omi + React</h1> <my-counter count={count} ref={myCounterRef}></my-counter> <div className="card"> <button onClick={() => setCount((count) => count + 1)}> count is {count} </button> </div> </> ) } export default App ``` ## Contributors <a href="https://github.com/Tencent/omi/graphs/contributors"> <img src="./assets/contributors.png" /> </a> ## License MIT © Tencent <!-- - [`tdesign-omi`](https://github.com/omijs/tdesign) - `[in progress...]`Cross framework components based on tdesign. [Preview](https://omijs.github.io/tdesign/) -->

简介

Omi - 前端跨框架跨平台框架 基于 Web Components 并支持 IE8+(omio),小程序(omi-kbone) 和 任意前端框架集成 展开 收起
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
JavaScript
1
https://gitee.com/Tencent/omi.git
git@gitee.com:Tencent/omi.git
Tencent
omi
omi
master

搜索帮助