ホームページ >WeChat アプレット >ミニプログラム開発 >WeChat ミニ プログラム開発チュートリアル: Mixin 拡張機能の追加

WeChat ミニ プログラム開発チュートリアル: Mixin 拡張機能の追加

不言
不言オリジナル
2018-06-23 09:37:022107ブラウズ

この記事では、主に mixin 拡張機能の追加に関する WeChat アプレット開発チュートリアルを紹介します。必要な場合は、それを共有します。

Mixin は、部分的に実装されたインターフェイスを使用するアイデアです。再利用。多重継承の問題を解決したり、関数を拡張したりするために使用できます。以下の記事では、WeChat ミニプログラムに mixin 拡張機能を追加するための関連情報を主に紹介します。必要な方は一緒に参照してください。

Mixin の紹介

Mixin (ウィービング) パターンは GOF の「デザイン パターン」の概要の 1 つではありませんが、このパターン (またはアイデア) のいくつかの応用例はさまざまな言語やフレームワークで見つけることができます。簡単に言うと、Mixin は完全または部分的に実装されたインターフェイスであり、その主な機能はコードの再利用を改善することです。

Mixin の概念は React と Vue でサポートされており、ビジネス ロジックの抽象化とコードの再利用に便利です。ただし、ネイティブ ミニ プログラム フレームワークは Mixin を直接サポートしません。まず、非常に実用的な要件を見てみましょう:

スタイル ハックを簡単に実行できるように、すべてのミニ プログラム ページに実行環境クラスを追加します。具体的には、小さなプログラムが異なる動作環境 (開発者ツール|iOS|Android) で実行される場合、プラットフォームの値は対応する動作環境の値 ("ios|android|devtools") になります

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

でのミックスインの使用の確認vue

記事の冒頭で述べた問題は、Mixin を使用して解決するのに非常に適しています。この要件を Vue の問題に変換しました。プラットフォーム スタイル クラスを各ルーティング ページに追加します (ただし、これは現実的ではないかもしれません)。実装のアイデアは、data:platform を各ルーティング コンポーネントに追加することです。コードは次のように実装されます: 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分类

  • data mixin

  • 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,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;
};
Page(createPage(configObj))
rrreee

このように、インデックスおよび詳細ルーティング ページの viewModel には、テンプレートで直接使用できる値プラットフォームがあります。

vueのmixin分類

  • データmixin

  • 通常のメソッドmixin

  • ライフサイクル メソッド mixin

コードで表現すると、次のようになります:

rrreee

vue での mixin マージ、実行戦略

mixin 間に重複がある場合、これらの mixin には特定の Merge が設定されますそして戦略を実行します。以下に示すように:

アプレットで mixin をサポートする方法

以前、vue の mixin に関する関連知識を確認しました。次に、ミニプログラムもミックスインをサポートし、vue で同じミックスイン機能を実現する必要があります。

実装アイデア

まずは公式ミニプログラムページの登録方法を見てみましょう: rrreee mixin設定を追加すると、上記の公式登録方法は次のようになります:

rrreee🎜🎜ここで特に注意すべき点が 2 つあります: 🎜🎜🎜
  • 🎜Page(configObj) - を設定します。 configObj を介したアプレット ページのデータ、メソッド、ライフサイクルなど🎜
  • 🎜onLoad メソッド - ページのメインの入り口🎜
🎜 mixin を有効にするには、それを configObjPage() に正式に渡す必要があります。実際、Page(configObj) は通常の関数呼び出しです: 🎜rrreee🎜 createPage メソッドでは、configObj 内のミックスインを前処理して、正しい設定を押すことができます。メソッドはマージされます。 configObj に格納され、最後に Page() に渡されます。これがミックスインの実装のアイデアです。 🎜🎜🎜🎜具体的な実装🎜🎜🎜🎜具体的なコードの実装については詳しく説明しません。次のコードを参照してください。より詳細なコード実装、その他の拡張機能、テストについては、github🎜rrreee🎜🎜概要🎜🎜🎜🎜1を参照してください。この記事では主に、小規模なプログラムに mixin サポートを追加する方法について説明します。実装のアイデアは、configObj🎜rrreee🎜2 を前処理することです。ミックスインの重複を処理するときは、vue と一貫性を保つようにしてください。🎜🎜 データ、メソッドはマージされ、コンポーネント自体が最も高い優先度を持ち、ミックスイン内で後で設定されるミックスインには優先度が高くなります。 🎜🎜🎜 ライフサイクルはマージされません。まずミックスイン内のライフサイクルを順番に実行し、次にコンポーネント自体のライフサイクルを実行します。 🎜🎜上記がこの記事の全内容です。その他の関連コンテンツについては、PHP 中国語 Web サイトをご覧ください。 🎜🎜関連する推奨事項: 🎜🎜🎜WeChat アプレットのページにジャンプする 2 つの方法🎜🎜🎜🎜🎜 タブ効果を実現する WeChat 開発用の JS 🎜🎜🎜🎜🎜🎜🎜

以上がWeChat ミニ プログラム開発チュートリアル: Mixin 拡張機能の追加の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。