1. 程式人生 > >小程式解決方案 Westore

小程式解決方案 Westore

## 資料流轉 先上一張圖看清 Westore 怎麼解決小程式資料難以管理和維護的問題: ![](https://img2018.cnblogs.com/blog/105416/201810/105416-20181008101849931-1044477325.jpg) 非純元件的話,可以直接省去 triggerEvent 的過程,直接修改 store.data 並且 update,形成縮減版單向資料流。 [Github: https://github.com/dntzhang/westore](https://github.com/dntzhang/westore) ## 元件 這裡說的元件便是自定義元件,使用原生小程式的開發格式如下: ```js Component({ properties: { }, data: { }, methods: { } }) ``` 使用 Westore 之後: ```js import create from '../../utils/create' create({ properties: { }, data: { }, methods: { } }) ``` 看著差別不大,但是區別: * Component 的方式使用 setData 更新檢視 * create 的方式直接更改 store.data 然後呼叫 update * create 的方式可以使用函式屬性,Component 不可以,如: ```js export default { data: { firstName: 'dnt', lastName: 'zhang', fullName:function(){ return this.firstName + this.lastName } } } ``` 繫結到檢視: ```jsx {{fullName}} ``` 小程式 setData 的痛點: * 使用 this.data 可以獲取內部資料和屬性值,但不要直接修改它們,應使用 setData 修改 * setData 程式設計體驗不好,很多場景直接賦值更加直觀方便 * setData 卡卡卡慢慢慢,JsCore 和 Webview 資料物件來回傳浪費計算資源和記憶體資源 * 元件間通訊或跨頁通訊會把程式搞得亂七八糟,變得極難維護和擴充套件 沒使用 westore 的時候經常可以看到這樣的程式碼: ![](https://img2018.cnblogs.com/blog/105416/201810/105416-20181008101748928-1344268518.png) 使用完 westore 之後: ![](https://img2018.cnblogs.com/blog/105416/201810/105416-20181008101801607-1744045780.png) 上面兩種方式也可以混合使用。 可以看到,westore 不僅支援直接賦值,而且 this.update 相容了 this.setData 的語法,但效能大大優於 this.setData,再舉個例子: ``` js this.store.data.motto = 'Hello Westore' this.store.data.b.arr.push({ name: 'ccc' }) this.update() ``` 等同於 ``` js this.update({ motto:'Hello Westore', [`b.arr[${this.store.data.b.arr.length}]`]:{name:'ccc'} }) ``` 這裡需要特別強調,雖然 this.update 可以相容小程式的 this.setData 的方式傳參,但是更加智慧,this.update 會先 Diff 然後 setData。原理: ![](https://img2018.cnblogs.com/blog/105416/201810/105416-20181008101817291-1689763155.jpg) ## 純元件 常見純元件由很多,如 tip、alert、dialog、pager、日曆等,與業務資料無直接耦合關係。 元件的顯示狀態由傳入的 props 決定,與外界的通訊通過內部 triggerEvent 暴露的回撥。 triggerEvent 的回撥函式可以改變全域性狀態,實現單向資料流同步所有狀態給其他兄弟、堂兄、姑姑等元件或者其他頁面。 Westore裡可以使用 `create({ pure: true })` 建立純元件(當然也可以直接使用 Component),比如 : ```js 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 與外界通訊 大型專案一定會包含純元件、業務元件。通過純元件,可以很好理解單向資料流。 ## 小程式外掛 ![](https://developers.weixin.qq.com/miniprogram/dev/devtools/image/devtools2/createplugin.png?t=18092720) 小程式外掛是對一組 JS 介面、自定義元件或頁面的封裝,用於嵌入到小程式中使用。外掛不能獨立執行,必須嵌入在其他小程式中才能被使用者使用;而第三方小程式在使用外掛時,也無法看到外掛的程式碼。因此,外掛適合用來封裝自己的功能或服務,提供給第三方小程式進行展示和使用。 外掛開發者可以像開發小程式一樣編寫一個外掛並上傳程式碼,在外掛釋出之後,其他小程式方可呼叫。小程式平臺會託管外掛程式碼,其他小程式呼叫時,上傳的外掛程式碼會隨小程式一起下載執行。 * [外掛開發者文件](https://developers.weixin.qq.com/miniprogram/dev/framework/plugin/development.html) * [外掛使用者文件](https://developers.weixin.qq.com/miniprogram/dev/framework/plugin/using.html) ### 外掛開發 Westore 提供的目錄如下: ``` |--components |--westore |--plugin.json |--store.js ``` 建立外掛: ```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 } ) } }) ``` 在你的小程式中使用元件: ```js ``` 這裡來梳理下小程式自定義元件外掛怎麼和使用它的小程式通訊: * 通過 properties 傳入更新外掛,通過 properties 的 observer 來更新外掛 * 通過 store.onChange 收集 data 的所有變更 * 通過 triggerEvent 來拋事件給使用外掛外部的小程式 這麼方便簡潔還不趕緊試試 [Westore外掛開發模板](https://github.com/dntzhang/westore/tree/master/packages/westore-plugin) ! ### 特別強調 外掛內所有元件公用的 store 和外掛外小程式的 store 是相互隔離的。 ### 原理 #### 頁面生命週期函式 | 名稱 | 描述 | | ------ | ------ | | onLoad | 監聽頁面載入 | | onShow | 監聽頁面顯示 | | onReady | 監聽頁面初次渲染完成 | | onHide | 監聽頁面隱藏 | | onUnload | 監聽頁面解除安裝 | #### 元件生命週期函式 | 名稱 | 描述 | | ------ | ------ | | created | 在元件例項進入頁面節點樹時執行,注意此時不能呼叫 setData | | attached | 在元件例項進入頁面節點樹時執行 | | ready | 在元件佈局完成後執行,此時可以獲取節點資訊(使用 SelectorQuery ) | | moved | 在元件例項被移動到節點樹另一個位置時執行 | | detached | 在元件例項被從頁面節點樹移除時執行 | 由於開發外掛時候的元件沒有 this.page,所以 store 是從根元件注入,而且可以在 attached 提前注入: ``` js 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](https://github.com/dntzhang/westore) ## License MIT [@dntzhang](https://github.com/dntzhang)