vue动态切换mixins

2,061 阅读1分钟

vue动态切换mixins

1.场景:

不同路由访问的页面,都需要加载相同的业务组件。本文拟通过切换mixins,达到解决组件复用的问题。

可复用代码:表单配置、表单操作(必填校验、业务逻辑校验)、最终提交的数据结构。

不可复用代码:表单提交的接口、后续步骤处理(页面跳转、相邻页面校验、错误定位)差异较大。

因此,决定把不可复用代码整理成两份mixin文件,根据需要加载对应的mixin。

2.方案:利用生命周期接口,在mixins内部定义的代码执行之前,改变mixin指向

2.1.方案1(失败):

2.1.1.beforeCreate内部,改变mixin指向

// form.vue 表单页
import MA from '../helper/mixinA.js'
import MB from '../helper/mixinB.js'
// ...
let finalMixin = MA
export default {
  mixins:[finalMixin],
  beforeCreate(){
    // 满足引用MB条件
    finalMixin = MB
  }
}

2.1.2.失败原因:

实例化组件new Vue,会执行实例的 _init(options) 方法,它首先会执行一个 merge options 的逻辑,此时就完成了mixins合并。

// _init(options)方法
Vue.prototype._init = function (options?: Object) {
  // merge options
  if (options && options._isComponent) {
    // optimize internal component instantiation
    // since dynamic options merging is pretty slow, and none of the
    // internal component options needs special treatment.
    initInternalComponent(vm, options)
  } else {
    vm.$options = mergeOptions(
      resolveConstructorOptions(vm.constructor),
      options || {},
      vm
    )
  }
  // ...
  // 执行beforeCreate
  callHook(vm, 'beforeCreate')
  // ...
}
export function mergeOptions (
  parent: Object,
  child: Object,
  vm?: Component
): Object {
  // ...
  // mixins合并
  if (child.mixins) {
    for (let i = 0, l = child.mixins.length; i < l; i++) {
      parent = mergeOptions(parent, child.mixins[i], vm)
    }
  }
  //  ...
  return options
}

2.1.3.待实践:beforeRouteEnter能否实现?此时组件实例还未创建。

beforeRouteEnter(to, from) {
    // 在渲染该组件的对应路由被验证前调用
    // 不能获取组件实例 `this` !
    // 因为当守卫执行时,组件实例还没被创建!
    if(/*满足引用MB条件*/){
      finalMixin = MB
    }
}

2.2.方案2(成功) :

在方案1失败原因的基础上,稍微调整了策略

2.2.1.mixins初始化前,改变mixin指向

简要描述:定义全局变量IS_SH,根据全局变量判断引入哪个mixin+beforeEach改变全局变量

// 全局变量定义 globalVariable.js
const globalVariable = { IS_SH: false }
const set_IS_SH = (flage) => { globalVariable.IS_SH = flag }
export const { globalVariable, set_IS_SH }

// 载入路由之前
router.beforeEach((to, from, next) => {
  if (/*满足引用MB条件*/) set_IS_SH(true)
  else set_IS_SH(false)
  next()
})

// form.vue 表单页
import MA from '../helper/mixinA.js'
import MB from '../helper/mixinB.js'
import { globalVariable } from 'xxxx/globalVariable.js'
// ...
let finalMixin = MA
export default {
  mixins:[globalVariable.IS_SH ? MB : MA]
  // ...
}

2.2.2.优化且暂未验证:动态导入 import()

上述导入方式是静态导入,但实际使用场景只存在二选一,因此可以考虑用 import()的方式加载模块。

// form.vue 表单页
export default {
  mixins:[globalVariable.IS_SH ? import('../helper/mixinA.js') : import('../helper/mixinB.js')]
  // ...
}