美文网首页
2.总结微信小程序9个优雅小技巧-(混入)复用属性/方法

2.总结微信小程序9个优雅小技巧-(混入)复用属性/方法

作者: XAKX | 来源:发表于2024-09-25 17:31 被阅读0次

    例子: https://gitee.com/akff/ak-mini-program

    实现效果: 无需重复定义,自动导入对应参数


    image.png

    核心代码

    // 1. 手动混入
    /**
     * 例子: (需要混入的页面中)
     * import initMixin from './mixin'
     * import 混入js from './js代码'
     * const mixin = initMixin()
     * mixin.use(引用混入js文件)
     * mixin.Page({
     *    data: {}
     *    onLoad: function(){
     *    }
     * })
     */
    
    // 2. 全局混入
    /**
     * 例子: (在app.js中执行, 也可导入已封装好的global-mixin.js)
     * import initMixin from './mixin'
     * // 混入-基础数据(可选)
     * import pageData from './global/pageData'
     * mixin(pageData)
     * // 注意:替换掉原Page方法
     * Page = mixin.Page
     */
    
    
    const originApp = App
    const originPage = Page
    const originComponent = Component
    
    // 混入-基础数据
    import pageData from './global/pageData'
    
    function init(...mixinFun) {
      // 可以用于拓展的生命周期
      const life = {
        App: ['preprocess', 'onLaunch', 'onShow', 'onHide', 'onError'],
        Page: ['preprocess', 'onLoad', 'onReady', 'onShow', 'onHide', 'onUnload', 'onPullDownRefresh', 'onReachBottom', 'onShareAppMessage'],
        Component: ['preprocess', 'created', 'attached', 'ready', 'moved', 'detached', 'error']
      };
    
      // 用于保存所有的拓展生命周期函数
      let lifeMixin = {};
      for (let key in life) {
        lifeMixin[key] = lifeMixin[key] || {};
        for (let lifeTime of life[key]) {
          lifeMixin[key][lifeTime] = [];
        }
      }
    
      // 基类对象
      // 在调用App、Page、Component前会被混入到对象中
      let base = {
        App: {},
        Page: {},
        Component: {}
      }
    
      let MpExtend = function (param) {
        // 允许接收数组形式的参数
        if (isArray(param)) {
          param.forEach(item => MpExtend(item));
          return;
        }
    
        for (const constructorName in param) {
          // constructorName 应当是[App, Page, Component] 中的一个
          if (!life[constructorName]) {
            warning(constructorName, 'not found');
            continue;
          }
    
          const option = Object.assign({}, param[constructorName]);
          // 如果是生命周期中的某一个,作为生命周期拓展
          for (const key in option) {
            if (lifeMixin[constructorName][key]) {
              lifeMixin[constructorName][key].push(option[key]);
              delete option[key];
            }
          }
          // 把剩余的属性混入到基类中
          mixin(base[constructorName], option);
        }
      }
    
      // 重新包装的 App、Page、Component构造函数
      // 虽然都是相似的代码但是这样更利于理解和修改
      const _App = decorate(originApp, function (option) {
        mixin(option, base.App);
        for (const lifeTime of life.App) {
          option[lifeTime] = decorate(option[lifeTime], ...lifeMixin.App[lifeTime]);
        }
        option['preprocess'] && option['preprocess'].call(option, option);
      });
      const _Page = decorate(originPage, function (option) {
        mixin(option, base.Page);
        for (const lifeTime of life.Page) {
          option[lifeTime] = decorate(option[lifeTime], ...lifeMixin.Page[lifeTime]);
        }
        option['preprocess'] && option['preprocess'].call(option, option);
      });
      const _Component = decorate(originComponent, function (option) {
        mixin(option, base.Component);
        for (const lifeTime of life.Component) {
          option[lifeTime] = decorate(option[lifeTime], ...lifeMixin.Component[lifeTime]);
        }
        option['preprocess'] && option['preprocess'].call(option, option);
      });
    
      // 装饰函数
      // 在调用原函数之前调用所有装饰器
      function decorate(f, ...decorators) {
        return function () {
          for (const decorator of decorators) {
            decorator && decorator.apply(this, arguments);
          }
          return f && f.apply(this, arguments);
        };
      }
    
      /**
       * 实现类似混入的效果
       * 类似 Object.assign, 但在遇见相同属性名均是对象时会递归进行合并而非直接覆盖
       * @param o
       * @param mix 可以传入多个
       * 注:如果存在引用循环递归会栈溢出
       */
      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;
      }
    
      function isObject(o) {
        return Object.prototype.toString.call(o) === "[object Object]";
      }
    
      function isArray(o) {
        return Object.prototype.toString.call(o) === "[object Array]";
      }
    
      function warning(...msg) {
        MpExtend.tips && console.warn('ak-mp-extend:', ...msg);
      }
    
      Object.assign(MpExtend, {
        mixin,
        decorate,
        lifeMixin,
        App: _App,
        Page: _Page,
        Component: _Component,
        warning,
        init,
        tips: true
      });
      // 遍历混入
      for(let item of mixinFun){
        MpExtend(item)
      }
      // 混入基础方法
      MpExtend(pageData)
      return MpExtend
    }
    // let MpExtend = init()
    export default init;
    

    方式一: 混入所有界面对象

    1. 在app.js中执行以下代码, 也可导入已封装好的global-mixin.js
    // global-mixin.js
    // 核心JS
    import initMixin from './mixin'
     // 混入-基础数据(可选)
    import pageData from './global/pageData'
    mixin(pageData)
    // 注意:替换掉原Page方法
    Page = mixin.Page
    

    方式二: 手动混入,在对应界面混入

            import initMixin from '../../../utils/mixins/mixin'
            import pageData from '../../../utils/mixins/global/pageData'
            const mixin = initMixin(pageData)
            
            mixin.Page({
              /**
               * 页面的初始数据
               */
              data: {},
              onLoad(options) {}
            })  
    

    例子: https://gitee.com/akff/ak-mini-program

    相关文章

      网友评论

          本文标题:2.总结微信小程序9个优雅小技巧-(混入)复用属性/方法

          本文链接:https://www.haomeiwen.com/subject/swwcrjtx.html