在小程序中實現全局混入,以混入的形式擴展小程序的api


GitHub:
https://github.com/WozHuang/mp-extend
相關文章:
小程序全局狀態管理,在頁面中獲取globalData和使用globalSetData
通過頁面預加載(preload)提升小程序的響應速度

主要目標

小程序本身的坑不少,開發時免不了需要引入或大或小的框架。而目前的小程序開發框架基本分為兩種,一種是以Taro、wePY這種以其他技術棧開發小程序,一種是在原有的小程序開發模式上進行擴展。

對於新建立的項目,選擇何種框架全憑喜好,可以優先考慮與團隊技術棧相關的開發框架。但是多數時候開發者還是使用小程序官方的開發方式,並且已經開發了一段時間並投入使用了,這時再考慮引入框架代價就有點大了,於是我就在尋找一個能夠在不改動現有代碼前提下擴展小程序api的框架。

尋找資料

參考了westore,omix,wxpage等基於小程序自身擴展的框架后,發現他們統一都是在APP、Page、Component構造函數上做文章,對頁面本身的PageOption進行操作,實現擴展api的功能。

小程序中有部分Vue和React的影子(data屬性,setData方法),而Vue和React都有mixin這種擴展組件的方式,於是便考慮在Page構造函數上做文章,提供全局混入的能力來擴展api。

代碼實現

我實現混入中的兩個主要函數:

1. 裝飾函數

使用裝飾方法對PageOption(Page函數調用時傳入的參數)中的生命周期函數(onLoad等)進行修改,調用混入的生命周期方法。

// 對原有函數進行修改,返回結果是原函數的返回結果
// 在調用原函數之前調用所有裝飾器
function decorate(f, ...decorators) {
  return function () {
    for (const decorator of decorators) {
      decorator && decorator.apply(this, arguments);
    }
    return f && f.apply(this, arguments);
  };
}

2. 合並混入對象

使用mixin函數將混入中的對象與PageOption原有的對象進行合並

/**
 * 實現混入的效果
 * 類似 Object.assign, 但在遇見相同屬性名均是對象時會遞歸進行合並而非直接覆蓋
 * 注:如果存在引用循環遞歸會棧溢出
 */
function mixin(o, ...mixs) {
  mixs.forEach(mix => {
    for (const key in mix) {
      // 兩個屬性都是對象則遞歸合並
      if (isObject(o[key]) && isObject(mix[key])) {
        mixin(o[key], mix[key]);
      } else {
        o[key] = o[key] || mix[key];
      }
    }
    // 拷貝symbol類型,(可惜小程序不支持)
    for (const sym of Object.getOwnPropertySymbols(mix)) {
      o[sym] = o[sym] || mix[sym];
    }
  });
  return o;
}

3. 重寫Page函數(App,Component同理)

在調用Page函數前將所有混入對象合並到PageOption中

// base.Page 頁面的基類,包含所有混入對象的非生命周期屬性
// lifeMixin.Page 包含所有混入對象的生命周期函數
// life.Page 一個數組包含Page所有的生命周期 ['onLoad', 'onShow', ...]

const _Page = decorate(Page, function (option) {
  // 合並非生命周期屬性
  mixin(option, base.Page);
  // 合並生命周期屬性
  for (const lifeTime of life.Page) {
    option[lifeTime] = decorate(option[lifeTime], ...lifeMixin.Page[lifeTime]);
  }
  // preprecess是擴展的生命周期,在Page函數調用前被調用,可以用於修改PageOption
  option['preproccess'] && option['preproccess'].call(option, option);
});

通過重寫Page函數在將混入對象合並到PageOption中實現全局混入的功能,最后只需要在現有代碼前加入一行 Page = _Page;,即可實現全局混入的能力而無需修改其他代碼。

使用示例

能夠方便地以全局混入的方式擴展api,以下是一個簡單示例:混入data屬性 和 添加PV統計功能

Page: {
  data: {
    exData: '所有頁面的data都會獲得exData屬性'
  },
  
  onLoad(){
    console.log(`PV統計: 在${formatTime(new Date())} 打開了頁面 ${this.__route__}`)
  }
}

參考資料
wxpage
omi
Vue mixins
微信小程序之提高應用速度小技巧


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM