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')]
// ...
}