搜尋
首頁微信小程式小程式開發微信小程式開發中關於增加mixin擴充功能的詳解

微信小程式開發中關於增加mixin擴充功能的詳解

Sep 12, 2017 am 11:27 AM
mixin小程式程式開發

Mixin是一種思想,用部分實現的介面來實現程式碼重複使用。可以用來解決多繼承的問題,又可以用來擴展功能。以下這篇文章主要給大家介紹了關於微信小程式增加mixin擴充功能的相關資料,需要的朋友可以參考借鑒,下面來一起看看吧。

Mixin簡介

Mixin(織入)模式並不是GOF的《設計模式》歸納中的一種,但在各種語言以及框架都會發現該模式(或思想)的一些應用。簡單來說,Mixin是帶有全部實現或部分實現的接口,其主要作用是更好的程式碼重複使用。

Mixin這個概念在React, Vue中都有支持,它為我們抽象業務邏輯,程式碼重複使用提供了方便。然而小程式原生框架並沒直接支援Mixin。我們先來看一個很實際的需求:

為所有小程式頁面增加運行環境class,以便做一些樣式hack。具體地說是小程式在不同的運行環境(開發者工具|iOS|Android)運行時,platform值為對應的運行環境值("ios|android|devtools")


<view class="{{platform}}">
 <!--页面模板-->
</view>

回顧vue中mixin的使用

文章開始提到的問題是非常適合使用Mixin來解決的。我們把這個需求轉換成一個Vue問題:在每個路由頁面中增加一個platform的樣式class(雖然這樣做可能沒實際意義)。實作想法就是為每個路由元件增加一個data: platform。程式碼實作如下:


// mixins/platform.js
const getPlatform = () => {
 // 具体实现略,这里mock返回&#39;ios&#39;
 return &#39;ios&#39;;
};

export default {
 data() {
 return {
  platform: getPlatform()
 }
 }
}


// 在路由组件中使用
// views/index.vue
import platform from &#39;mixins/platform&#39;;

export default {
 mixins: [platform],
 // ...
}


// 在路由组件中使用
// views/detail.vue
import platform from &#39;mixins/platform&#39;;
export default {
 mixins: [platform],
 // ...
}

這樣,在index,detail兩個路由頁的viewModel上就都有platform這個值,可以直接在模板中使用。

vue中mixin分類

  • #datain

  • normal method mixin

  • lifecycle method mixin

#用程式碼表示的話,就如:


export default {
 data () {
 return {
  platform: &#39;ios&#39;
 }
 },
 methods: {
 sayHello () {
  console.log(`hello!`)
 }
 },

 created () {
 console.log(`lifecycle3`)
 }
}

vue中mixin合併,執行原則

如果mixin間出現了重複,這些mixin會有具體的合併,執行策略。如下圖:

如何讓小程式支援mixin

在前面,我們回顧了vue中mixin的相關知識。現在我們要讓小程式也支援mixin,實作vue中一樣的mixin功能。

實現想法

我們先看一下官方的小程式頁面註冊方式:


Page({
 data: {
 text: "This is page data."
 },
 onLoad: function(options) {
 // Do some initialize when page load.
 },
 onReady: function() {
 // Do something when page ready.
 },
 onShow: function() {
 // Do something when page show.
 },
 onHide: function() {
 // Do something when page hide.
 },
 onUnload: function() {
 // Do something when page close.
 },
 customData: {
 hi: &#39;MINA&#39;
 }
})

假如我們加入mixin配置,上面的官方註冊方式會變成:


Page({
 mixins: [platform],
 data: {
 text: "This is page data."
 },
 onLoad: function(options) {
 // Do some initialize when page load.
 },
 onReady: function() {
 // Do something when page ready.
 },
 onShow: function() {
 // Do something when page show.
 },
 onHide: function() {
 // Do something when page hide.
 },
 onUnload: function() {
 // Do something when page close.
 },
 customData: {
 hi: &#39;MINA&#39;
 }
})

這裡有兩個點,我們要特別注意:

  • Page(configObj) - 透過configObj設定小程式頁面的data, method, lifecycle等

  • # onLoad方法- 頁面main入口

要想讓mixin中的定義有效,就要在configObj正式傳給Page()之前做文章。其實Page(configObj)就是一個普通的函數調用,我們加個中間方法:


Page(createPage(configObj))

在createPage這個方法中,我們可以預處理configObj中的mixin,把其中的設定用正確的方式合併到configObj上,最後交給Page() 。這就是實作mixin的思路。

具體實作

具體程式碼實作就不再贅述,可以看下面的程式碼。更詳細的程式碼實現,更多擴展,測試可以參考github


/**
 * 为每个页面提供mixin,page invoke桥接
 */

const isArray = v => Array.isArray(v);
const isFunction = v => typeof v === &#39;function&#39;;
const noop = function () {};

// 借鉴redux https://github.com/reactjs/redux
function compose(...funcs) {
 if (funcs.length === 0) {
 return arg => arg;
 }

 if (funcs.length === 1) {
 return funcs[0];
 }

 const last = funcs[funcs.length - 1];
 const rest = funcs.slice(0, -1);
 return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args));
}


// 页面堆栈
const pagesStack = getApp().$pagesStack;

const PAGE_EVENT = [&#39;onLoad&#39;, &#39;onReady&#39;, &#39;onShow&#39;, &#39;onHide&#39;, &#39;onUnload&#39;, &#39;onPullDownRefresh&#39;, &#39;onReachBottom&#39;, &#39;onShareAppMessage&#39;];
const APP_EVENT = [&#39;onLaunch&#39;, &#39;onShow&#39;, &#39;onHide&#39;, &#39;onError&#39;];

const onLoad = function (opts) {
 // 把pageModel放入页面堆栈
 pagesStack.addPage(this);

 this.$invoke = (pagePath, methodName, ...args) => {
 pagesStack.invoke(pagePath, methodName, ...args);
 };

 this.onBeforeLoad(opts);
 this.onNativeLoad(opts);
 this.onAfterLoad(opts);
};

const getMixinData = mixins => {
 let ret = {};

 mixins.forEach(mixin => {
 let { data={} } = mixin;

 Object.keys(data).forEach(key => {
  ret[key] = data[key];
 });
 });

 return ret;
};

const getMixinMethods = mixins => {
 let ret = {};

 mixins.forEach(mixin => {
 let { methods={} } = mixin;

 // 提取methods
 Object.keys(methods).forEach(key => {
  if (isFunction(methods[key])) {
  // mixin中的onLoad方法会被丢弃
  if (key === &#39;onLoad&#39;) return;

  ret[key] = methods[key];
  }
 });

 // 提取lifecycle
 PAGE_EVENT.forEach(key => {
  if (isFunction(mixin[key]) && key !== &#39;onLoad&#39;) {
  if (ret[key]) {
   // 多个mixin有相同lifecycle时,将方法转为数组存储
   ret[key] = ret[key].concat(mixin[key]);
  } else {
   ret[key] = [mixin[key]];
  }
  }
 })
 });

 return ret;
};

/**
 * 重复冲突处理借鉴vue:
 * data, methods会合并,组件自身具有最高优先级,其次mixins中后配置的mixin优先级较高
 * lifecycle不会合并。先顺序执行mixins中的lifecycle,再执行组件自身的lifecycle
 */

const mixData = (minxinData, nativeData) => {
 Object.keys(minxinData).forEach(key => {
 // page中定义的data不会被覆盖
 if (nativeData[key] === undefined) {
  nativeData[key] = minxinData[key];
 }
 });

 return nativeData;
};

const mixMethods = (mixinMethods, pageConf) => {
 Object.keys(mixinMethods).forEach(key => {
 // lifecycle方法
 if (PAGE_EVENT.includes(key)) {
  let methodsList = mixinMethods[key];

  if (isFunction(pageConf[key])) {
  methodsList.push(pageConf[key]);
  }

  pageConf[key] = (function () {
  return function (...args) {
   compose(...methodsList.reverse().map(f => f.bind(this)))(...args);
  };
  })();
 }

 // 普通方法
 else {
  if (pageConf[key] == null) {
  pageConf[key] = mixinMethods[key];
  }
 }
 });

 return pageConf;
};

export default pageConf => {

 let {
 mixins = [],
 onBeforeLoad = noop,
 onAfterLoad = noop
 } = pageConf;

 let onNativeLoad = pageConf.onLoad || noop;
 let nativeData = pageConf.data || {};

 let minxinData = getMixinData(mixins);
 let mixinMethods = getMixinMethods(mixins);

 Object.assign(pageConf, {
 data: mixData(minxinData, nativeData),
 onLoad,
 onBeforeLoad,
 onAfterLoad,
 onNativeLoad,
 });

 pageConf = mixMethods(mixinMethods, pageConf);

 return pageConf;
};

小結

#1 、本文主要講如何為小程式增加mixin支援。實作想法為:預處理configObj


Page(createPage(configObj))

2、處理mixin重複時,與vue一致:

      data, methods會合併,元件本身俱有最高優先權,其次mixins中後配置的mixin優先權較高。

      lifecycle不會合併。先依序執行mixins中的lifecycle,再執行元件本身的lifecycle。

總結

#

以上是微信小程式開發中關於增加mixin擴充功能的詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱工具

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能