擴展微信小程序 Mixins 實現

2021-12-13 ejtoia

Vue 提供了一種非常靈活的混入(mixins)方式,用於分發 Vue 組件中可復用的功能。微信小程序的 Component 使用 behaviors 可以實現類似 Vue 中的 mixins。

Page 創建頁面不支持 behaviors 或 mixins,怎麼在不同頁面實現代碼復用與共享呢?

有兩種方式:

使用 Component 創建頁面

頁面本身就可以看做是組件,將 Page 構造器直接替換為 Component 創建頁面,可以使用 behaviors 實現頁面邏輯的復用。

Component 構造器與 Page 構造器的主要區別是把頁面的方法定義在methods: {}對象中。

my-behavior.js

export default Behavior({
  data: {
    userAge: 25
  },
  created: function () {
    console.log('mixin created')
  },
  methods: {
    printOutUserAge () {
      console.log('mixin data userAge:', this.data.userAge)
    }
  }

使用 Behavior 來包裝混入對象。

index.js


import myBehavior from "./my-behavior"

Component({
  behaviors: [myBehavior],
  data: {
    name: 'ejtoia'
  },

  created: function () {
    console.log('Page create')
    this.printOutUserName()
  },

  methods: {
    printOutUserName() {
      this.printOutUserAge()
      console.log(this.data.name)
    },
    onShareAppMessage: function () {
      // 頁面被用戶分享時執行
    },
    onReachBottom: function() {
      // 頁面觸底執行
    }
  }
})

index 頁面 log 依次輸出為:

mixin created
Page created
mixin data userAge:25
ejtoia

Index 頁面的 onShareAppMessage、onReachBottom 等等方法都定義在 Component 構造器的 methods 對象中。

behaviors 同名欄位的覆蓋和組合規則查閱官方文檔:

https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/behaviors.html擴展 Page 的 mixins 選項

原理很好理解。先保存原始的 Page 構造器函數,然後重新定義新的 Page 構造器函數。

這相當於加入一個中間函數,用來處理 options 選項對象的 mixins 值,把 mixins 中的每一個混入對象(包括生命周期函數、data、方法等)按照一定的規則合併到 options 選項對象中,最後再調用原始 Page(options) 構造器函數創建頁面。

wx-mixins.js 入口文件

// 保存原始的 Page
const originPage = Page

// 重新定義 Page
Page = options => {
  // 處理 mixins
  const mixins = options.mixins
  if (Array.isArray(mixins)) {
    options = mergeOptions(mixins, options)
    delete options.mixins
  }
  // 執行原始的 Page
  originPage(options)
}

將 mixins 中每一個混入對象都合併到 options 選項對象中,在開始 mergeOptions 函數之前,先來規定一下 mixins 的合併規則。

mixins 同名欄位的覆蓋與合併規則

同名生命周期函數都會被調用,混入對象的生命周期函數在頁面生命周期函數之前被調用

data 對象在內部會進行淺合併,並在命名發生衝突時以頁面數據優先

混入對象的屬性或方法命名衝突時,頁面定義的屬性或方法優先

mergeOptions 實現
// Page 生命周期函數列表
const pageHooks = [
  "onLoad",
  "onShow",
  "onReady",
  "onHide",
  "onUnload",
  "onPullDownRefresh",
  "onReachBottom",
  "onShareAppMessage",
  "onPageScroll",
  "onResize",
  "onTabItemTap"
]

const hasOwnProperty = Object.prototype.hasOwnProperty;
const toString = Object.prototype.toString

function toRawType(value) {
  return toString.call(value).slice(8, -1);
}

function isPlainObject(value) {
  return toRawType(value) === "Object";
}

function isFunction(value) {
  return toRawType(value) === "Function";
}

function hasOwn(obj, key) {
  return hasOwnProperty.call(obj, key);
}


function mergeOptions (mixins, options) {
  mixins.forEach(mixin => {
    if (!isPlainObject(mixin)) {
      throw new Error("typeof mixin must be plain object") 
    }

    // 混入對象中嵌套混入對象,遞歸合併
    if (mixin.mixins) {
      mixin = mergeOptions(mixin.mixins, mixin, hooks)
    }

    // 處理混入對象中每一個值, 可能是生命周期函數、可能是 data 或 方法
    for (const key in mixin) {
      // 暫存頁面中初始的值
      const originValue = options[key]
      // 暫存混入對象的值
      const mixinValue = mixin[key]

      // 處理混入對象的生命周期函數
      if (pageHooks.includes(key)) {
        if (!isFunction(mixinValue)) {
          throw new Error(`typeof ${key} must be function`)
        }
        // 重寫頁面的生命周期函數
        options[key] = function () {
          let res;
          // 先執行混入對象的生命周期函數
          res = mixinValue.apply(this, arguments)
          // 後執行頁面中的生命周期函數
          if (originValue) res = originValue.apply(this, arguments)
          return res
        }
      }
      // 混入對象的值是對象
      else if (isPlainObject(mixinValue)) {
        options[key] = {
          ...mixinValue,
          ...originValue
        }
      }
      // 混入對象的屬性或方法
      else {
        // 頁面中不存在同名的屬性或方法時,才使用混入對象的屬性或方法
        if (!hasOwn(options, key)) {
          options[key] = mixinValue
        }
      }
    }
  })

  return options
}

使用 mixins

小程序入口文件 app.js 中引入 wx-mixins.js 擴展的實現後,那麼所有使用 Page 創建的頁面都可以使用 mixins 選項。

app.js

import "./wx-mixins"

my-mixins.js

export default {
  data: {
    userAge: 25
  },
  onLoad: function () {
    console.log('mixin onLoad')
  },
  printOutUserAge () {
    console.log('mixin data userAge:', this.data.userAge)
  }

默認導出一個混入對象,包含多個頁面共用的生命周期、data 和方法。

index.js

import myMixin from "./my-mixins"

Page({
  mixins: [index_mixins],
  data: {
    name: 'ejtoia'
  },

  onLoad: function () {
    console.log('Page onLoad')
    this.printOutUserName()
  },

  printOutUserName() {
    this.printOutUserAge()
    console.log(this.data.name)
  },

  onShareAppMessage: function () {
    // 頁面被用戶分享時執行
  },
  onReachBottom: function() {
    // 頁面觸底執行
  }
})

Index 頁面使用混入對象後的 log 輸出結果:

mixin onLoad
Page onLoad
mixin data userAge:25
ejtoia

mixins 混入對象相比 Component 創建頁面,可以直接使用 Page 創建頁面,不需要將屬性或方法定義到 methods: {} 中。

總結

在微信小程序中 Page 使用比較頻繁,為了方便頁面的邏輯代碼復用,擴展 Page 的 mixins 選項,它最核心的實現是 mergeOptions 合併函數。

也可以給 App、Component 構造器函數也擴展 mixins 選項,因為 App 使用不多,Component 已經內置了 behaviors 選項,所以這兩個擴展 mixins 的意義不是很大。

參考https://github.com/kallsave/wx-miniapp-mixinshttps://cn.vuejs.org/v2/guide/mixins.htmlhttps://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/behaviors.html

相關焦點

  • Vue Mixin
    上面是通過 Object.assign 來實現的,那麼 mixins 內的方法會覆蓋base 內的內容。如果這不是你期望的結果,可以調換 mixin 和 base 的位置。組合大於繼承 && DRY想像一下上面的例子用繼承如何實現?由於 js 是單繼承語言,只能一層層繼承。寫起來很繁瑣。這裡就體現了 mixin 的好處。
  • 深入淺出 Vue Mixin
    上面是通過 Object.assign 來實現的,那麼 mixins 內的方法會覆蓋base 內的內容。如果這不是你期望的結果,可以調換 mixin 和 base 的位置。組合大於繼承 && DRY想像一下上面的例子用繼承如何實現?由於 js 是單繼承語言,只能一層層繼承。寫起來很繁瑣。這裡就體現了 mixin 的好處。
  • 【Vuejs】887- 深入淺出 Vue Mixin
    上面是通過 Object.assign 來實現的,那麼 mixins 內的方法會覆蓋base 內的內容。如果這不是你期望的結果,可以調換 mixin 和 base 的位置。組合大於繼承 && DRY想像一下上面的例子用繼承如何實現?由於 js 是單繼承語言,只能一層層繼承。寫起來很繁瑣。這裡就體現了 mixin 的好處。
  • 傻傻搞不懂React的Mixin、HOC、Render Props
    引入了隱式的依賴關係(Mixins introduce implicit dependencies)你可能會寫一個有狀態的組件,然後你的同事可能添加一個讀取這個組件state的mixin。你會記得更新這個mixin來讀取props而不是state嗎?如果此時,其它組件也在使用這個mixin呢?
  • 打開新世界,瀏覽器擴展程序如何逆天?
    其實我們可以換種方式理解擴展程序,它有點類似於微信中的小程序,寄生在瀏覽器中。當然,兩者並不能完全等同,擴展程序需要下載而小程序不用,兩者技術原理也天差地別。
  • 星巴克上線微信小程序
    摘要:近日,星巴克通過其官方微信公眾號發布消息稱,星巴克微信小程序開放公測,其功能包含「用星說」、專星送服務以及搜索附近的門店功能,消費者可以在此平臺進行下單。
  • 微信小程序中如何使用WebSocket實現長連接(含完整源碼)
    1、前言微信小程序提供了一套在微信上運行小程序的解決方案,有比較完整的框架、組件以及 API,在這個平臺上面的想像空間很大。騰訊雲研究了一番之後,發現微信支持 WebSocket 還是很值得玩味的。這個特性意味著我們可以做一些實時同步或者協作的小程序。
  • 美妝品牌如何借小程序實現私域破局?
    2018年,innisfree聯手微信支付打造了品牌第一家智慧美妝店,為消費者帶來包括「魔鏡快速上妝」、「智能肌膚測試」、「商品推薦」與「刷臉會員支付」等創新美妝體驗。線上,innisfree全面擁抱小程序矩陣,藉助微信生態內的立體化觸點,逐步將會員服務、銷售和導購運營搬到了線上,實現線上線下一體化管理。
  • 號角聯盟視頻號視頻擴展連結生成製作流量主廣告小程序開發
    號角聯盟視頻號視頻擴展連結生成製作流量主廣告小程序開發用戶使用簡單流程:打開小程序——上傳視頻——生成擴展連結——發布視頻號(利潤視頻號上半集,擴展連結下半季,點擊觀看)——好友打開連結觀看視頻,彈出廣告
  • 微信小程序在哪裡打開?
    在點餐時,掃一下餐桌上的小程序碼,就能自助下單;在線上購物時,使用小程序商城,就能在微信內完成商品瀏覽、下單等操作……這都是微信小程序帶給我們的便捷。現在使用小程序的人越來越多,但有些用戶會發現,自己的微信裡並沒有小程序。為什麼微信裡沒小程序呢?這是因為你沒有打開過小程序。
  • 微信小程序直播登場,與平臺直播有何不同?
    原標題:微信小程序直播登場,與平臺直播有何不同?姍姍來遲的微信小程序直播,與抖音、快手、淘寶等平臺直播有著怎樣的區別?商家應該如何選擇適合自己的平臺?今天我們來詳細對比。微信小程序直播開啟公測了。
  • 開源 Java 微服務應用程式框架 KivaKit 簡介
    給定上面的偵聽器鏈,C 和 B 實現了中繼器,最終的對象 A 實現了偵聽器。在鏈中的每個類中,偵聽器鏈擴展為:listener.listenTo(broadcaster)為了向感興趣的偵聽器傳輸消息,這裡從 Broadcaster 繼承了一些針對常見消息類型的便利方法:
  • ...擴展計劃主要依靠線下門店和線上小程序 實現線上線下相融合發展
    來源:同花順金融研究中心同花順(300033)金融研究中心12月8日訊,有投資者向穩健醫療(300888)提問, 您好,能否概述一下「津梁生活」後續門店的擴展計劃和團隊概況?擴展計劃主要依靠線下門店和線上小程序,實現線上線下相融合發展。津梁生活精選全球好物,以天然,科學,健美為品牌主張,倡導「由內而外,表裡如一」的健康和美麗,其品牌主張適應消費升級趨勢。其理念與全棉時代「舒適,健康,環保」相近。津梁生活將依靠全棉時代的資源,如商場資源關係,共享粉絲和共享數據化運營,實現發展。
  • 重磅 | 小程序可以實現AR效果了
    首個小程序AR動態試妝的美妝品牌小程序也正式落地。當然,更多的品牌商戶和服務商也可以通過能力的接入,一起來玩「AR」。基於小程序攝像頭幀處理能力,小程序可實現AR效果了。AR也叫「增強現實」,是一種將虛擬信息融合到真實世界的能力。掌握了AR的小程序會怎樣呢?一個字,立體。
  • 微信小程序:製作微信小程序需要什麼?怎麼做?
    小程序離線促銷程序:如何做微信小程序。1.小程序可以通過不同行業的聯盟(具有共同的消費者群體)推廣。其次,通過特定場景進行離線促銷(分散更多場景進行地面促銷)微信有趣的小程序遊戲。微信小程序:製作微信小程序需要什麼?怎麼做?首先,您必須闡明您的功能要求:電子商務小程序?預訂小程序?這只是一個小型商業展覽嗎?微信小程序可以賺錢嗎?二是考慮預算:制定不同的備忘單程序,資金投入也大不相同,微信小程序是最熱門的遊戲。
  • 星巴克將專星送搬上微信小程序
    北京商報訊(記者 郭詩卉)5月24日,記者發現,星巴克上線了全新的微信小程序,其功能包含「用星說」、專星送服務以及搜索附近的門店功能,消費者可以在此平臺進行下單。星巴克相關負責人在接受北京商報記者採訪時表示,5月22日,為進一步滿足顧客一站式的第四空間場景交互需求,星巴克上線了全新的星巴克微信小程序,其中涵蓋「用星說」體驗、專星送服務以及搜索附近的門店功能。
  • 微信點餐支付小程序開發
    小程序的開發,讓我們可以通過更為簡單的方式實現最為便捷的消費,餐飲市場一直是兵家必爭之地,但是常常甜品店、美食店都是客滿排隊,吃貨只能望穿秋水。微信餐飲點餐支付小程序的出現,讓顧客可以直接進入小程序自助點餐並完成支付。不用排隊等候,提高用戶體驗。微信點餐支付小程序,微信點餐小程序開發。
  • 微信小程序再出重磅功能!可實現AR效果 口紅試色已可用
    【TechWeb】7月7日消息,據微信官方發布的消息,小程序可實現AR效果了,包括AR試穿、AR逛展等各種體驗。
  • 微信小商店和小程序的區別是什麼
    微信小商店是微信團隊中新增的一個電商功能,可以幫助店主提升銷售能力,那麼微信小商店和小程序有哪些不同之處,這裡我們來一起看下微信小商店和小程序的不同之處介紹。
  • 微信小程序是什麼 怎麼查找微信小程序商店【詳解】
    微信小程序有商店嗎_微信小程序商店在哪裡 微信小程序正式版在今天已經上線,很多小夥伴也都去體驗了,不少玩家都在關注商店的問題,下面小編就來給大家介紹一下微信小程序商店解析,希望能幫到大家!  微信小程序有商店嗎    在公開課上,張小龍明確表示,微信不會做小程序商店,小程序在微信裡面也沒有入口。