1. 程式人生 > >小程序解決方案 Westore - 組件、純組件、插件開發

小程序解決方案 Westore - 組件、純組件、插件開發

stc 數據 ice 參數 detail 解決方案 註意 stringify oba

數據流轉

先上一張圖看清 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

小程序解決方案 Westore - 組件、純組件、插件開發