修改Component函数 ,添加自定义组件基础配置
发布于 3 年前 作者 guoguiying 1374 次浏览 来自 分享

需求由来

在写自定义组件过程中,往往会有一些重复代码需要书写,如下

    Component({
      data: {
          xxx: 'xxx',
          _xxx:'_xxx',
          globalData:getApp().globalData
      },
      options: {
          addGlobalClass: true,
          multipleSlots: true,
          pureDataPattern:/^_/,
          virtualHost: true
      },
      behaviors:['xxx'],
      externalClasses: ['class'],
      properties: {
          style: String
      },
      lifetimes:{
        attached(){
          console.log(this.data.globalData)
          //this.theme('bluesky') 设置主题颜色
          //......
        }
      }
    })

刚刚开始还可以通过将部分属性打包成 behaviors在需要的组件中加载,但还是有些属性可能是全局自定义组件都需要用到的,单独在每次创建自定义组件的时候加behavior还是感觉浪费时间。找了下没找到官方为Comonents函数全局注入属性的类似behavior混入配置,于是想自己写一个。

整体逻辑

建立一个函数(mixinComponent) 内部合并mixinOpt(要合并的属性对象) 和 curOpt(初始化组件页时候传入的配置对象)为一个新的options对象,再调用Component(options )。这个函数要在app.js中先调用。

分享代码

app.js

import {mixinComponent} from './utils/mixinComponent'
App({
  globalData:{
    test:'hello world'
  }
})
// 因为我这里要加入全局globalData,所以在App之后调用了
mixinComponent({
  data: {
      xxx: 'xxx',
      _xxx:'_xxx',
      globalData:getApp().globalData
  },
  options: {
      addGlobalClass: true,
      multipleSlots: true,
      pureDataPattern:/^_/,
      virtualHost: true
  },
  externalClasses: ['class'],
  properties: {
      style: String
  },
  lifetimes:{
    attached(){
      console.log(this.data.globalData.test)
      //this.setTheme('bluesky') 设置主题颜色
    }
  }
})

Component.js

Component({
  data: {
    name:'zhao'
  },
  methods: {
  },
  lifetimes: {
    attached() {
      console.log(this.data.test,this.data.globalData.test)
    }
  }
})

mixinComponet.js

// 定义一个混合组件函数,传入的参数类型和Component一致
export let mixinComponent = function (mixinOpt) {
    //保存原始Component
    let originComponent = Component;
    //重新定义Component
    Component = function (opt) {
        //把建立Component的配置对象和混入的配置对象合并
        let newOpt = mergeOpt(opt, mixinOpt);
        //返回 原始Component 参数为混合完毕的新配置对象
        return originComponent(newOpt);
    };
    //为了满足函数返回类型需要 返回String
    return '';
};
function mergeLifetimes(curOptFunc, mixinLifetimesFunc, curOpt, lifetimesName) {
    const temp = curOptFunc;
    curOpt[lifetimesName] = function (e) {
        mixinLifetimesFunc.call(this, e);
        temp.call(this, e);
    };
}
/**
 *
 * [@param](/user/param) curOpt 要混入的配置对象
 * [@param](/user/param) mixinOpt 创立组件时候输入的配置对象
 * [@param](/user/param) namespace 为了提示时候的命名空间
 */
function mergeOpt(curOpt, mixinOpt, namespace = '') {
    //深度克隆mixinOpt是因为 他是个引用值,都在这个对象上面做混入,会冲突的。
    let keys = Object.keys(mixinOpt);
    namespace = namespace || 'mixinObj';
    keys.forEach((propName) => {
        if (!curOpt.hasOwnProperty(propName)) { //如果没有这个属性
            curOpt[propName] = mixinOpt[propName]; //直接赋值过去
        }
        else { //有这个属性的情况下
            if (propName === 'behaviors' || propName === 'externalClasses') { //这个属性是behaviors 合并
                curOpt[propName] = [...new Set([...curOpt[propName], ...mixinOpt[propName]])];
            }
            else if (propName === 'lifetimes') { //这个属性是lifetimes 合并
                var lifenameArr = Object.keys(mixinOpt.lifetimes); //要合并的生命周期函数
                lifenameArr.forEach(ele => {
                    if (!curOpt.lifetimes[ele]) { //如果原来没有,直接赋值过去,
                        curOpt.lifetimes[ele] = mixinOpt.lifetimes[ele];
                    }
                    else { //如果原来有 合并在一起
                        mergeLifetimes(curOpt.lifetimes[ele], mixinOpt.lifetimes[ele], curOpt.lifetimes, ele);
                    }
                });
            }
            else if (typeof mixinOpt[propName] !== 'object' || propName === 'pureDataPattern') { //如果不是对象
                throw Error(`${namespace}中有${propName}这个属性了`);
            }
            else { //这个属性是对象 递归
                curOpt[propName] = mergeOpt(curOpt[propName], mixinOpt[propName], namespace + '.' + propName);
            }
        }
    });
    return curOpt;
}

总结

  1. 当自定义组件的配置文件中与mixinOpt冲突的时候会提示报错
  2. 因为我是用ts写的,mixinOpt的类型检查会在输入错误属性类型提前报错,上面是编译为js后的代码,需要注意mixinOpt中输入无效字段可能出现未知错误。
  3. 配置合并中可能有未判断的字段,或者后续官方增加的配置也要加入进去。
  4. 如果您看错哪里写的问题,请浏览回复。
  5. 如果文章对您有所帮助,请点赞,后续会多多发帖。
1 回复
回到顶部