Skip to content

Commit 3d8ff70

Browse files
committed
OMI V7 is Here 🎉
0 parents  commit 3d8ff70

File tree

121 files changed

+16856
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

121 files changed

+16856
-0
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.js linguist-vendored

.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
node_modules
10+
dist
11+
*.local
12+
# Editor directories and files
13+
.vscode/*
14+
!.vscode/extensions.json
15+
.idea
16+
.DS_Store
17+
*.suo
18+
*.ntvs*
19+
*.njsproj
20+
*.sln
21+
*.sw?
22+
build
23+
docs
24+
coverage

LICENSE

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
Tencent is pleased to support the open source community by making Omi available.
2+
Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved.
3+
If you have downloaded a copy of the Omi binary from Tencent, please note that the Omi binary is licensed under the MIT License.
4+
If you have downloaded a copy of the Omi source code from Tencent, please note that Omi source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of Omi into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within Omi.
5+
A copy of the MIT License is included in this file.
6+
7+
## Open Source Software Licensed Under the MIT License:
8+
9+
preact v8.2.7
10+
Copyright (c) 2017 Jason Miller
11+
12+
construct-style-sheets-polyfill v3.0.1
13+
Copyright (c) 2018 alshakero
14+
15+
weakmap-polyfill v2.0.4
16+
Copyright (c) 2015-2021 polygonplanet
17+
18+
## The MIT License (MIT)
19+
20+
Permission is hereby granted, free of charge, to any person obtaining a copy
21+
of this software and associated documentation files (the "Software"), to deal
22+
in the Software without restriction, including without limitation the rights
23+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24+
copies of the Software, and to permit persons to whom the Software is
25+
furnished to do so, subject to the following conditions:
26+
27+
The above copyright notice and this permission notice shall be included in all
28+
copies or substantial portions of the Software.
29+
30+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36+
SOFTWARE.

README.CN.md

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
[English](./README.md) | 简体中文
2+
3+
<p align="center"><img src="https://omijs.github.io/home/assets/logo.svg" alt="omi" width="100"/></p>
4+
<h2 align="center">Omi - Web Components 框架</h2>
5+
6+
- 📶 信号 **Signal** 驱动的响应式编程
7+
-**微小的**尺寸,**极速的**性能
8+
- 💯 面向对象编程(OOP) 和 数据驱动编程(DOP) 两种范式都支持
9+
- 🌐 结合 **JSX** 语法和 **Web Components** 的强大组合,让组件化开发更简单、更高效
10+
- 💒 使用 **Constructable Stylesheets** 轻松管理和共享样式
11+
12+
```tsx
13+
import { render, signal, tag, Component, h } from 'omi'
14+
15+
const count = signal(0)
16+
17+
function add() {
18+
count.value++
19+
}
20+
21+
function sub() {
22+
count.value--
23+
}
24+
25+
@tag('counter-demo')
26+
class CounterDemo extends Component {
27+
static css = 'span { color: red; }'
28+
29+
render() {
30+
return (
31+
<>
32+
<button onClick={sub}>-</button>
33+
<span>{count.value}</span>
34+
<button onClick={add}>+</button>
35+
</>
36+
)
37+
}
38+
}
39+
40+
render(<counter-demo />, document.body)
41+
```
42+
43+
44+
## 安装
45+
46+
```bash
47+
npm i omi
48+
```
49+
50+
快速创建 Omi + Vite + TS/JS 项目:
51+
52+
```bash
53+
$ npx omi-cli init my-app # 或者创建js项目: npx omi-cli init-js my-app
54+
$ cd my-app
55+
$ npm start # develop
56+
$ npm run build # release
57+
```
58+
59+
###
60+
61+
- 核心包
62+
- [`omi`](https://github.com/Tencent/omi/tree/master/packages/omi) - Omi 框架的实现代码。
63+
- [`omi-cli`](https://github.com/omijs/cli) - 快速创建 Omi + Vite + TS/JS 项目。
64+
- 入门套件 (未发布到 npm)
65+
- [`omi-starter-ts`](https://github.com/Tencent/omi/tree/master/packages/omi-starter-ts) - 基于Vite + Omi + TypeScript 的模板。
66+
- [`omi-starter-js`](https://github.com/Tencent/omi/tree/master/packages/omi-starter-js) - 基于Vite + Omi + JavaScript 的模板。
67+
- Components
68+
- [`tdesign-icons-omi`](https://github.com/omijs/tdesign-icons) - 基于 TDesign 和 Omi 的跨框架 icon 集合。
69+
- [`tdesign-omi`](https://github.com/omijs/tdesign) - `[进行中...]`基于 TDesign 和 Omi 的跨框架 组件 集合。 [点击这里预览一下](https://omijs.github.io/tdesign/)
70+
- 综合性例子 (未发布到 npm)
71+
- [`snake-game-2tier`](https://github.com/Tencent/omi/tree/master/packages/snake-game-2tier) - 基于 Omi `Signal` class 两层架构的贪吃蛇游戏。
72+
- [`snake-game-3tier`](https://github.com/Tencent/omi/tree/master/packages/snake-game-3tier) - 基于 Omi 响应是函数三层架构的贪吃蛇游戏。
73+
74+
## 使用
75+
76+
### TodoApp 使用响应式函数
77+
78+
> 数据驱动编程
79+
80+
在数据驱动编程中,我们将重点放在数据本身和对数据的操作上,而不是数据所在的对象或数据结构。这种编程范式强调的是数据的变化和流动,以及如何响应这些变化。基于响应式函数的 TodoApp 就是一个很好的例子,它使用了响应式编程的概念,当数据(即待办事项列表)发生变化时,UI 会自动更新以反映这些变化。
81+
82+
83+
```tsx
84+
import { render, signal, computed, tag, Component, h } from 'omi'
85+
86+
const todos = signal([
87+
{ text: 'Learn OMI', completed: true },
88+
{ text: 'Learn Web Components', completed: false },
89+
{ text: 'Learn JSX', completed: false },
90+
{ text: 'Learn Signal', completed: false }
91+
])
92+
93+
const completedCount = computed(() => {
94+
return todos.value.filter(todo => todo.completed).length
95+
})
96+
97+
const newItem = signal('')
98+
99+
function addTodo() {
100+
// api a,不会重新创建数组
101+
todos.value.push({ text: newItem.value, completed: false })
102+
todos.update() // 非值类型的数据更新需要手动调用 update 方法
103+
104+
// api b, 和上面的 api a 效果一样,但是会创建新的数组
105+
// todos.value = [...todos.value, { text: newItem.value, completed: false }]
106+
107+
newItem.value = '' // 值类型的数据更新需会自动 update
108+
}
109+
110+
function removeTodo(index: number) {
111+
todos.value.splice(index, 1)
112+
todos.update() // 非值类型的数据更新需要手动调用 update 方法
113+
}
114+
115+
@tag('todo-list')
116+
class TodoList extends Component {
117+
onInput = (event: Event) => {
118+
const target = event.target as HTMLInputElement
119+
newItem.value = target.value
120+
}
121+
122+
render() {
123+
return (
124+
<>
125+
<input type="text" value={newItem.value} onInput={this.onInput} />
126+
<button onClick={addTodo}>Add</button>
127+
<ul>
128+
{todos.value.map((todo, index) => {
129+
return (
130+
<li>
131+
<label>
132+
<input
133+
type="checkbox"
134+
checked={todo.completed}
135+
onInput={() => {
136+
todo.completed = !todo.completed
137+
todos.update()
138+
}}
139+
/>
140+
{todo.completed ? <s>{todo.text}</s> : todo.text}
141+
</label>
142+
{' '}
143+
<button onClick={() => removeTodo(index)}>❌</button>
144+
</li>
145+
)
146+
})}
147+
</ul>
148+
<p>Completed count: {completedCount.value}</p>
149+
</>
150+
)
151+
}
152+
}
153+
154+
render(<todo-list />, document.body)
155+
```
156+
157+
158+
### TodoApp 使用信号类 Signal
159+
160+
> 面向对象编程
161+
162+
在面向对象编程中,我们将重点放在对象上,对象包含了数据和操作数据的方法。这种编程范式强调的是对象之间的交互和协作,以及如何通过对象的封装、继承和多态性来组织和管理代码。基于响应式函数的 TodoApp 也可以使用面向对象的方式来实现,例如,我们可以创建一个 TodoList 类,这个类包含了待办事项列表的数据和操作这些数据的方法,以及一个 `update` 方法来更新 UI。
163+
164+
165+
166+
```tsx
167+
import { render, Signal, tag, Component, h, computed } from 'omi'
168+
169+
type Todo = { text: string, completed: boolean }
170+
171+
class TodoApp extends Signal<{ todos: Todo[], filter: string, newItem: string }> {
172+
completedCount: ReturnType<typeof computed>
173+
174+
constructor(todos: Todo[] = []) {
175+
super({ todos, filter: 'all', newItem: '' })
176+
this.completedCount = computed(() => this.value.todos.filter(todo => todo.completed).length)
177+
}
178+
179+
addTodo = () => {
180+
// api a
181+
this.value.todos.push({ text: this.value.newItem, completed: false })
182+
this.value.newItem = ''
183+
this.update()
184+
185+
// api b, same as api a
186+
// this.update((value) => {
187+
// value.todos.push({ text: value.newItem, completed: false })
188+
// value.newItem = ''
189+
// })
190+
}
191+
192+
toggleTodo = (index: number) => {
193+
const todo = this.value.todos[index]
194+
todo.completed = !todo.completed
195+
this.update()
196+
}
197+
198+
removeTodo = (index: number) => {
199+
this.value.todos.splice(index, 1)
200+
this.update()
201+
}
202+
}
203+
204+
const todoApp = new TodoApp([
205+
{ text: 'Learn OMI', completed: true },
206+
{ text: 'Learn Web Components', completed: false },
207+
{ text: 'Learn JSX', completed: false },
208+
{ text: 'Learn Signal', completed: false }
209+
])
210+
211+
@tag('todo-list')
212+
class TodoList extends Component {
213+
onInput = (event: Event) => {
214+
const target = event.target as HTMLInputElement
215+
todoApp.value.newItem = target.value
216+
}
217+
218+
render() {
219+
const { todos } = todoApp.value
220+
const { completedCount, toggleTodo, addTodo, removeTodo } = todoApp
221+
return (
222+
<>
223+
<input type="text" value={todoApp.value.newItem} onInput={this.onInput} />
224+
<button onClick={addTodo}>Add</button>
225+
<ul>
226+
{todos.map((todo, index) => {
227+
return (
228+
<li>
229+
<label>
230+
<input
231+
type="checkbox"
232+
checked={todo.completed}
233+
onInput={() => toggleTodo(index)}
234+
/>
235+
{todo.completed ? <s>{todo.text}</s> : todo.text}
236+
</label>
237+
{' '}
238+
<button onClick={() => removeTodo(index)}>❌</button>
239+
</li>
240+
)
241+
})}
242+
</ul>
243+
<p>Completed count: {completedCount.value}</p>
244+
</>
245+
)
246+
}
247+
}
248+
249+
render(<todo-list />, document.body)
250+
```
251+
252+
这里不讨论哪种方式(DOP,OOP)的好坏,使用 omi 两种方式都可以任意选择。
253+
254+
## 自动导入 h
255+
256+
vite.config.js:
257+
258+
```tsx
259+
import { defineConfig } from 'vite'
260+
261+
export default defineConfig({
262+
esbuild: {
263+
jsxInject: "import { h } from 'omi'",
264+
jsxFactory: "h",
265+
jsxFragment: "h.f"
266+
}
267+
})
268+
```
269+
270+
你可以在构建时候注入代码,这样就不用手动导出 `h`
271+
272+
## 集成 Twind
273+
274+
```tsx
275+
import { Component, define, h } from 'omi'
276+
277+
import install from '@twind/with-web-components'
278+
import { defineConfig } from '@twind/core'
279+
import presetAutoprefix from '@twind/preset-autoprefix'
280+
import presetTailwind from '@twind/preset-tailwind'
281+
const withTwind = install(defineConfig({
282+
presets: [presetAutoprefix(), presetTailwind()],
283+
}))
284+
285+
define('my-app', class extends withTwind(Component) {
286+
render() {
287+
return <h1 class="text-3xl font-bold underline">Hello world!</h1>
288+
}
289+
})
290+
```
291+
292+
## 贡献者
293+
294+
<a href="https://github.com/Tencent/omi/graphs/contributors">
295+
<img src="https://contrib.rocks/image?repo=Tencent/omi" />
296+
</a>
297+
298+
## 微信群
299+
300+
<img src="./wechat.png" alt="omi" width="300"/></p>
301+
302+
## License
303+
304+
MIT © Tencent

0 commit comments

Comments
 (0)