數據流轉 先上一張圖看清 Westore 怎麼解決小程式數據難以管理和維護的問題: 非純組件的話,可以直接省去 triggerEvent 的過程,直接修改 store.data 並且 update,形成縮減版單向數據流。 "Github: https://github.com/dntzhang/we ...
數據流轉
先上一張圖看清 Westore 怎麼解決小程式數據難以管理和維護的問題:
非純組件的話,可以直接省去 triggerEvent 的過程,直接修改 store.data 並且 update,形成縮減版單向數據流。
Github: https://github.com/dntzhang/westore
組件
這裡說的組件便是自定義組件,使用原生小程式的開發格式如下:
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>
小程式 setData 的痛點:
- 使用 this.data 可以獲取內部數據和屬性值,但不要直接修改它們,應使用 setData 修改
- setData 編程體驗不好,很多場景直接賦值更加直觀方便
- setData 卡卡卡慢慢慢,JsCore 和 Webview 數據對象來回傳浪費計算資源和記憶體資源
- 組件間通訊或跨頁通訊會把程式搞得亂七八糟,變得極難維護和擴展
沒使用 westore 的時候經常可以看到這樣的代碼:
使用完 westore 之後:
上面兩種方式也可以混合使用。
可以看到,westore 不僅支持直接賦值,而且 this.update 相容了 this.setData 的語法,但性能大大優於 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'}
})
這裡需要特別強調,雖然 this.update 可以相容小程式的 this.setData 的方式傳參,但是更加智能,this.update 會先 Diff 然後 setData。原理:
純組件
常見純組件由很多,如 tip、alert、dialog、pager、日曆等,與業務數據無直接耦合關係。
組件的顯示狀態由傳入的 props 決定,與外界的通訊通過內部 triggerEvent 暴露的回調。
triggerEvent 的回調函數可以改變全局狀態,實現單向數據流同步所有狀態給其他兄弟、堂兄、姑姑等組件或者其他頁面。
Westore里可以使用 create({ pure: true })
創建純組件(當然也可以直接使用 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)})
}
}
})
需要註意的是,加上 pure : true
之後就是純組件,組件的 data 不會被合併到全局的 store.data 上。
組件區分業務組件和純組件,他們的區別如下:
- 業務組件與業務數據緊耦合,換一個項目可能該組件就用不上,除非非常類似的項目
- 業務組件通過 store 獲得所需參數,通過更改 store 與外界通訊
- 業務組件也可以通過 props 獲得所需參數,通過 triggerEvent 與外界通訊
- 純組件與業務數據無關,可移植和復用
- 純組件只能通過 props 獲得所需參數,通過 triggerEvent 與外界通訊
大型項目一定會包含純組件、業務組件。通過純組件,可以很好理解單向數據流。
小程式插件
小程式插件是對一組 JS 介面、自定義組件或頁面的封裝,用於嵌入到小程式中使用。插件不能獨立運行,必須嵌入在其他小程式中才能被用戶使用;而第三方小程式在使用插件時,也無法看到插件的代碼。因此,插件適合用來封裝自己的功能或服務,提供給第三方小程式進行展示和使用。
插件開發者可以像開發小程式一樣編寫一個插件並上傳代碼,在插件發佈之後,其他小程式方可調用。小程式平臺會托管插件代碼,其他小程式調用時,上傳的插件代碼會隨小程式一起下載運行。
插件開發
Westore 提供的目錄如下:
|--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 }
)
}
})
在你的小程式中使用組件:
<list auth-key="{{authKey}}" bind:listChange="onListChange" />
這裡來梳理下小程式自定義組件插件怎麼和使用它的小程式通訊:
- 通過 properties 傳入更新插件,通過 properties 的 observer 來更新插件
- 通過 store.onChange 收集 data 的所有變更
- 通過 triggerEvent 來拋事件給使用插件外部的小程式
這麼方便簡潔還不趕緊試試 Westore插件開發模板 !
特別強調
插件內所有組件公用的 store 和插件外小程式的 store 是相互隔離的。
原理
頁面生命周期函數
名稱 | 描述 |
---|---|
onLoad | 監聽頁面載入 |
onShow | 監聽頁面顯示 |
onReady | 監聽頁面初次渲染完成 |
onHide | 監聽頁面隱藏 |
onUnload | 監聽頁面卸載 |
組件生命周期函數
名稱 | 描述 |
---|---|
created | 在組件實例進入頁面節點樹時執行,註意此時不能調用 setData |
attached | 在組件實例進入頁面節點樹時執行 |
ready | 在組件佈局完成後執行,此時可以獲取節點信息(使用 SelectorQuery ) |
moved | 在組件實例被移動到節點樹另一個位置時執行 |
detached | 在組件實例被從頁面節點樹移除時執行 |
由於開發插件時候的組件沒有 this.page,所以 store 是從根組件註入,而且可以在 attached 提前註入:
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)
}
總結
- 組件 - 對 WXML、WXSS 和 JS 的封裝,與業務耦合,可復用,難移植
- 純組件 - 對 WXML、WXSS 和 JS 的封裝,與業務解耦,可復用,易移植
- 插件 - 小程式插件是對一組 JS 介面、自定義組件或頁面的封裝,與業務耦合,可復用
Star & Fork 小程式解決方案
https://github.com/dntzhang/westore
License
MIT @dntzhang