小程式解決方案 Westore - 元件、純元件、外掛開發

【當耐特】發表於2018-10-08

資料流轉

先上一張圖看清 Westore 怎麼解決小程式資料難以管理和維護的問題:

小程式解決方案 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 之後:

小程式解決方案 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。原理:

小程式解決方案 Westore - 元件、純元件、外掛開發

純元件

常見純元件由很多,如 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 與外界通訊

大型專案一定會包含純元件、業務元件。通過純元件,可以很好理解單向資料流。

小程式外掛

小程式解決方案 Westore - 元件、純元件、外掛開發

小程式外掛是對一組 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

相關文章