>  기사  >  위챗 애플릿  >  WeChat 애플릿 개발 시 믹스인 확장 추가에 대한 자세한 설명

WeChat 애플릿 개발 시 믹스인 확장 추가에 대한 자세한 설명

黄舟
黄舟원래의
2017-09-12 11:27:252294검색

Mixin은 부분적으로 구현된 인터페이스를 사용하여 코드 재사용을 달성하는 아이디어입니다. 다중 상속 문제를 해결하는 데 사용할 수 있으며 기능을 확장하는 데 사용할 수 있습니다. 다음 글에서는 위챗 미니 프로그램에 믹스인 확장 기능을 추가하는 방법에 대해 주로 소개합니다. 필요한 친구들이 참고하면 됩니다.

Mixin 소개

Mixin(weaving) 패턴은 GOF의 "디자인 패턴" 요약에 포함되어 있지 않지만, 이 패턴(또는 아이디어)의 일부 응용 프로그램은 다양한 언어와 프레임워크에서 찾을 수 있습니다. 간단히 말해서 Mixin은 전체 또는 부분 구현이 가능한 인터페이스이며 주요 기능은 더 나은 코드 재사용입니다.

Mixin의 개념은 React 및 Vue에서 지원되며 비즈니스 로직을 추상화하고 코드 재사용에 편리함을 제공합니다. 그러나 네이티브 미니 프로그램 프레임워크는 Mixin을 직접 지원하지 않습니다. 먼저 매우 실용적인 요구 사항을 살펴보겠습니다.

모든 미니 프로그램 페이지에 실행 환경 클래스를 추가하면 일부 스타일 해킹을 더 쉽게 할 수 있습니다. 구체적으로, 미니 프로그램이 서로 다른 운영 환경(Developer Tools|iOS|Android)에서 실행될 때 플랫폼 값은 해당 운영 환경 값("ios|android|devtools")이 됩니다.


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

Review in vue 믹스인의 사용

글 시작 부분에서 언급한 문제는 믹스인을 사용하여 해결하기에 매우 적합합니다. 우리는 이 요구 사항을 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

  • data mixin


  • normal method mixin
  • 의 mixin 분류 lifecycle method mixin

코드로 표현하면 다음과 같습니다:


rrreee

Vue mixin 병합, 실행 전략

mixin 사이에 중복이 있는 경우 이러한 mixin은 구체적인 합병 및 실행 전략이 있습니다. 아래와 같이:

🎜🎜🎜애플릿 지원 mixin을 만드는 방법🎜🎜🎜🎜이전에 vue에서 mixin 관련 지식을 검토했습니다. 이제 미니 프로그램도 mixin을 지원하고 vue에서 동일한 mixin 기능을 실현해야 합니다. 🎜🎜🎜구현 아이디어🎜🎜🎜먼저 공식 미니 프로그램 페이지 등록 방법을 살펴보겠습니다: 🎜🎜🎜🎜rrreee🎜mixin 구성을 추가하면 위 공식 등록 방법은 다음과 같습니다: 🎜🎜🎜🎜rrreee🎜🎜여기서 특별히 주의해야 할 두 가지 사항이 있습니다: 🎜🎜🎜
  • 🎜Page(configObj) - configObj🎜
  • 🎜onLoad 메소드를 통해 미니 프로그램 페이지의 데이터, 메소드, 라이프사이클 등을 구성합니다. - 페이지의 주요 입구🎜
🎜If 믹스인의 정의가 유효하도록 하려면 configObj가 공식적으로 Page()에 전달되기 전에 소란을 피워야 합니다. 실제로 Page(configObj)는 일반적인 함수 호출입니다. 중간 메서드를 추가합니다: 🎜🎜🎜🎜rrreee🎜 createPage 메서드에서는 configObj의 믹스인을 전처리하고 그 안에 구성을 넣을 수 있습니다. . 올바른 방법으로 configObj에 병합하고 마지막으로 Page() 에 넘겨주세요. 이것이 믹스인을 구현하는 아이디어이다. 🎜🎜🎜🎜특정 구현🎜🎜🎜🎜구체적인 코드 구현은 아래에서 자세히 설명하지 않습니다. 더 자세한 코드 구현, 더 많은 확장 기능 및 테스트를 보려면 github🎜🎜🎜🎜rrreee🎜🎜🎜Summary🎜🎜🎜🎜1을 참조하세요. 이 글에서는 주로 작은 프로그램에 믹스인 지원을 추가하는 방법에 대해 설명합니다. 구현 아이디어는 다음과 같습니다. configObj🎜🎜🎜🎜🎜rrreee🎜2. 믹스인 중복을 처리할 때 vue와 일관성을 유지하세요. 🎜🎜 데이터와 메서드가 병합되고 구성 요소 자체가 가장 높은 우선 순위를 가지며 그 다음이 믹스인입니다. 먼저 믹스인에서 구성됩니다. 🎜🎜🎜 수명 주기는 병합되지 않습니다. 먼저 믹스인의 수명주기를 순차적으로 실행한 다음 구성 요소 자체의 수명주기를 실행합니다. 🎜🎜🎜🎜요약🎜🎜🎜

위 내용은 WeChat 애플릿 개발 시 믹스인 확장 추가에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.