Store 是 Omi 内置的中心化数据仓库,他解决了下面两个问题:javascript
而这一切都是在运行时搞定。css
import { render, WeElement, define } from 'omi'
define('my-counter', class extends WeElement {
static use = [
{ count: 'count' }
]
add = () => this.store.add()
sub = () => this.store.sub()
addIfOdd = () => {
if (this.use.count % 2 !== 0) {
this.store.add()
}
}
addAsync = () => {
setTimeout(() => this.store.add(), 1000)
}
render() {
return (
<p> Clicked: {this.use.count} times {' '} <button onClick={this.add}>+</button> {' '} <button onClick={this.sub}>-</button> {' '} <button onClick={this.addIfOdd}> Add if odd </button> {' '} <button onClick={this.addAsync}> Add async </button> </p>
)
}
})
render(<my-counter />, 'body', { data: { count: 0 }, sub() { this.data.count-- }, add() { this.data.count++ }, }) 复制代码
这是一个简单的例子,说明了 store 体系的基本用法:html
static use
声明依赖的 pathstore
经过 render 的第三个参数从根节点注入到全部组件。这里在书写过程当中会出现两种方式,一种是将全部数据和逻辑放在 store 里,一种是将部分共享数据放在 store 里,这里没有强制要求使用哪一种方式,omi 这两种能力都有,开发者偏心哪一种方式就使用哪一种方式。前端
Store 里的 data:java
{
count: 0,
arr: ['china', 'tencent'],
motto: 'I love omi.',
userInfo: {
firstName: 'dnt',
lastName: 'zhang',
age: 18
}
}
复制代码
Static use:node
static use = [
'count', //直接字符串,可经过 this.use[0] 访问
'arr[0]', //也支持 path,可经过 this.use[1] 访问
//支持 json
{
//alias,可经过 this.use.reverseMotto 访问
reverseMotto: [
'motto', //path
target => target.split('').reverse().join('') //computed
]
},
{ name: 'arr[1]' }, //{ alias: path },可经过 this.use.name 访问
{
//alias,可经过 this.use.fullName 访问
fullName: [
['userInfo.firstName', 'userInfo.lastName'], //path array
(firstName, lastName) => firstName + lastName //computed
]
},
]
复制代码
下面看看 JSX 中使用:git
...
...
render() {
return (
<div> <button onClick={this.sub}>-</button> <span>{this.use[0]}</span> <button onClick={this.add}>+</button> <div> <span>{this.use[1]}</span> <button onClick={this.rename}>rename</button> </div> <div>{this.use.reverseMotto}</div><button onClick={this.changeMotto}>change motto</button> <div>{this.use.name}</div> <div>{this.use[3]}</div> <div> {this.use.fullName} <button onClick={this.changeFirstName}>change first name</button> </div> </div>
)
}
...
...
复制代码
若是不带有 alias ,你也能够直接经过 this.store.data.xxx
访问。github
当 store.data
发生变化,依赖变动数据的组件会进行更新,举例说明 Path 命中规则:json
Proxy Path(由数据更改产生) | static use 中的 path | 是否更新 |
---|---|---|
abc | abc | 更新 |
abc[1] | abc | 更新 |
abc.a | abc | 更新 |
abc | abc.a | 不更新 |
abc | abc[1] | 不更新 |
abc | abc[1].c | 不更新 |
abc.b | abc.b | 更新 |
以上只要命中一个条件就能够进行更新!浏览器
总结: 只要注入组件的 path 等于 use 里声明 或者在 use 里声明的其中 path 子节点下就会进行更新!
import { define, WeElement } from 'omi'
import '../my-list'
define('my-sidebar', class extends WeElement {
static css = require('./_index.css')
static use = [
'menus',
'sideBarShow',
'lan'
]
render() {
const [menus, sideBarShow, lan] = this.use
return (
<div class={`list${sideBarShow ? ' show' : ''}`}> {menus[lan].map((menu, index) => ( <my-list menu={menu} index={index} /> ))} </div> ) } }) 复制代码
这里举了个例子使用 ES2015+ 语法 const [xx, xxx] = xxxx
的语法快速赋值。上面是从 omi docs 的源码里截取的部分。感兴趣的能够看看源码。omi 官网已经使用 omi 6.0 重写了。
回顾 Omi 从 1.0 到 6.0:
1.0 使用的动态模板引擎,是图灵完备的,能够表达一切你想表达的结构。因为是运行时,无法转虚拟 DOM,必定要转也能够,开销大,因此缺点很明显,视图更新开销大,依赖真实 DOM 之间的的 diff,另一个缺点就是动态模板引擎(指令、模板语法均可以动态拼接)须要在脑海里二次转换,书写起来不够直观、智能提示也没有,不如 JSX 直接干净和智能。而为何要这么设计,从整个发展历程来看离不开三个字: 运行时。
Omi 的设计 1.0 败也败在运行时,成也成在运行时。从 2.0 开始,除了 JSX 的部分(固然能够直接 hyperscript),其他所有 运行时 搞定:
而到了 9210 年,JSX 也出现了运行时的替代方案:htm 。
为什么如此偏心运行时?而不交给编译器去作?这个仁者见仁,智者见智,并且有个权衡在里面。
当运行时的开销对于用户体验能够忽略不计,那么就选择运行时去作
运行时的好处很是明显,不须要任何构建工具、编译工具,就能够在浏览器、node、javascript core 或者任何 javascript 环境直接运行。凭什么让我学那么多构建工具、凭什么和一堆工具耦合在一块儿,我就是纯粹的 js,想在哪里跑均可以轻松复制粘贴或者直接 import/require 过去,而不强制带上任何工具。固然这里不是反对编译工具对前端带来的价值,omi-cli、omip、omi-mp 都大量使用了编译工具,只是没有编译工具,omi 也能运行良好,简单移植,好比 es module,好比 deno,直接 import 直接使用。