先(xian)上一(yi)張圖看清 Westore 怎么解決小程序數據難以管理和維護(hu)的問題:

非純組(zu)件的話(hua),可以直接省(sheng)去(qu) triggerEvent 的過程,直接修改 store.data 并(bing)且(qie) update,形成(cheng)縮減版單向數據流。
這(zhe)里說的組(zu)件(jian)便(bian)是自定義組(zu)件(jian),使用原生(sheng)小(xiao)程序(xu)的開發格式如下:
Component({
properties: { },
data: { },
methods: { }
})
使用 Westore 之后:
import create from '../../utils/create'
create({
properties: { },
data: { },
methods: { }
})
|
看著差別不大,但是區別:
Component 的方式使用 setData 更新視圖
create 的方式直接更改 store.data 然后調用 update
create 的方式可以使用函數屬性,Component 不可以,如:
export default {
data: {
firstName: 'dnt',
lastName: 'zhang',
fullName:function(){
return this.firstName + this.lastName
}
}
}
|
綁定到視圖:
<view>{{fullName}}</view>
小程(cheng)序 setData 的(de)痛點:
沒使(shi)用 westore 的(de)時(shi)候經常可以看(kan)到這樣的(de)代碼:

使用完 westore 之后:

上面兩種(zhong)方式也可以混合使用。
可以看到,westore 不(bu)僅(jin)支(zhi)持直(zhi)接賦值(zhi),而且(qie) this.update 兼容了(le) this.setData 的(de)語法,但性能(neng)大(da)大(da)優于 this.setData,再舉個例子:
this.store.data.motto = 'Hello Westore'
this.store.data.b.arr.push({ name: 'ccc' })
this.update()
|
等同于
this.update({
motto:'Hello Westore',
[`b.arr[${this.store.data.b.arr.length}]`]:{name:'ccc'}
})
|
這(zhe)里需(xu)要特(te)別強調,雖然 this.update 可以兼容小程序的(de) this.setData 的(de)方(fang)式傳參(can),但是更加智能(neng),this.update 會先 Diff 然后 setData。原理(li):

常(chang)見純組件(jian)由很多(duo),如 tip、alert、dialog、pager、日歷(li)等(deng),與業務數據無直(zhi)接(jie)耦合關系。
組件(jian)的(de)(de)顯示狀態由傳(chuan)入的(de)(de) props 決定,與外界的(de)(de)通訊通過(guo)內部 triggerEvent 暴露的(de)(de)回(hui)調。
triggerEvent 的回調函數可以(yi)改變全(quan)局狀態,實現單向數據流同步所有狀態給其他兄弟(di)、堂(tang)兄、姑姑等組(zu)件(jian)或者其他頁面。
Westore里(li)可以使用 create({ pure: true }) 創建(jian)純組件(當然也可以直接(jie)使用 Component),比如 :
import create from '../../utils/create'
create({
pure : true,
properties: {
text: {
type: String,
value: '',
observer(newValue, oldValue) { }
}
},
data: {
privateData: 'privateData'
},
ready: function () {
console.log(this.properties.text)
},
methods: {
onTap: function(){
this.store.data.privateData = '成功修改 privateData'
this.update()
this.triggerEvent('random', {rd:'成功發起單向數據流' + Math.floor( Math.random()*1000)})
}
}
})
|
需要(yao)注意的(de)是(shi),加上 pure : true 之后就(jiu)是(shi)純組件(jian),組件(jian)的(de) data 不會被(bei)合并(bing)到(dao)全局的(de) store.data 上。
組件(jian)區分業務組件(jian)和純組件(jian),他們的(de)區別如(ru)下:
大型項目一定(ding)會包含純(chun)組件、業(ye)務組件。通過純(chun)組件,可以很(hen)好理解單向數據流(liu)。

小程序插(cha)件(jian)(jian)(jian)是對一組(zu) JS 接口、自定(ding)義組(zu)件(jian)(jian)(jian)或頁面的(de)封裝,用(yong)(yong)(yong)于嵌入到小程序中使用(yong)(yong)(yong)。插(cha)件(jian)(jian)(jian)不能獨立運行,必(bi)須嵌入在其他小程序中才能被用(yong)(yong)(yong)戶使用(yong)(yong)(yong);而第(di)三(san)(san)方(fang)小程序在使用(yong)(yong)(yong)插(cha)件(jian)(jian)(jian)時,也無法看到插(cha)件(jian)(jian)(jian)的(de)代碼。因此,插(cha)件(jian)(jian)(jian)適合用(yong)(yong)(yong)來封裝自己的(de)功能或服務(wu),提供(gong)給(gei)第(di)三(san)(san)方(fang)小程序進行展示(shi)和使用(yong)(yong)(yong)。
插(cha)(cha)(cha)件開(kai)發者可以像開(kai)發小程(cheng)序一樣編(bian)寫一個插(cha)(cha)(cha)件并上(shang)傳代(dai)碼(ma),在插(cha)(cha)(cha)件發布(bu)之(zhi)后,其(qi)他小程(cheng)序方可調(diao)用。小程(cheng)序平臺會(hui)托管插(cha)(cha)(cha)件代(dai)碼(ma),其(qi)他小程(cheng)序調(diao)用時,上(shang)傳的插(cha)(cha)(cha)件代(dai)碼(ma)會(hui)隨(sui)小程(cheng)序一起(qi)下載運行。
Westore 提供的目(mu)錄如下:
|--components
|--westore
|--plugin.json
|--store.js
創建插件:
import create from '../../westore/create-plugin'
import store from '../../store'
//最外層容器節點需要傳入 store,其他組件不傳 store
create(store, {
properties:{
authKey:{
type: String,
value: ''
}
},
data: { list: [] },
attached: function () {
// 可以得到插件上聲明傳遞過來的屬性值
console.log(this.properties.authKey)
// 監聽所有變化
this.store.onChange = (detail) => {
this.triggerEvent('listChange', detail)
}
// 可以在這里發起網絡請求獲取插件的數據
this.store.data.list = [{
name: '電視',
price: 1000
}, {
name: '電腦',
price: 4000
}, {
name: '手機',
price: 3000
}]
this.update()
//同樣也直接和兼容 setData 語法
this.update(
{ 'list[2].price': 100000 }
)
}
})
|
在你的小程序中使用組件(jian):
<list auth-key="{{authKey}}" bind:listChange="onListChange" />
這里來梳(shu)理下小(xiao)程序自(zi)定(ding)義組件插件怎么(me)和(he)使用它的小(xiao)程序通訊:
這么方便簡潔還不(bu)趕緊試(shi)試(shi) Westore插件開(kai)發模板 !
插件(jian)(jian)內所有(you)組件(jian)(jian)公用的 store 和插件(jian)(jian)外小程序的 store 是相互隔離(li)的。


由于開發插件(jian)時候的(de)組件(jian)沒有 this.page,所以(yi) store 是從(cong)根組件(jian)注(zhu)入,而且可以(yi)在 attached 提前(qian)注(zhu)入:
export default function create(store, option) {
let opt = store
if (option) {
opt = option
originData = JSON.parse(JSON.stringify(store.data))
globalStore = store
globalStore.instances = []
create.store = globalStore
}
const attached = opt.attached
opt.attached = function () {
this.store = globalStore
this.store.data = Object.assign(globalStore.data, opt.data)
this.setData.call(this, this.store.data)
globalStore.instances.push(this)
rewriteUpdate(this)
attached && attached.call(this)
}
Component(opt)
}
|