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 直接使用。