1、问题起源
由于 Vue 基于组件化的设计,得益于这个思想,我们在 Vue 的项目中可以通过封装组件提高代码的复用性。根据我目前的使用心得,知道 Vue 拆分组件至少有两个优点:
1、代码复用。
2、代码拆分
在基于 element-ui 开发的项目中,可能我们要写出一个类似的调度弹窗功能,很容易编写出以下代码:
我是中国地图的弹窗
我是美国地图的弹窗
我是英国地图的弹窗
打开中国地图
打开美国地图
打开英国地图
export default {
name: "View",
data() {
return {
// 对百度地图和谷歌地图的一些业务处理代码 省略
cnMapVisible: false,
usaMapVisible: false,
ukMapVisible: false,
};
},
methods: {
// 对百度地图和谷歌地图的一些业务处理代码 省略
openChina() {},
openUSA() {},
openUK() {},
},
};
上述代码存在的问题非常多,首先当我们的弹窗越来越多的时候,我们会发现此时需要定义越来越多的变量去控制这个弹窗的显示或者隐藏。
由于当我们的弹窗的内部还有业务逻辑需要处理,那么此时会有相当多的业务处理代码夹杂在一起(比如我调用中国地图我需要用高德地图或者百度地图,而调用美国、英国地图我只能用谷歌地图,这会使得两套业务逻辑分别位于一个文件,严重加大了业务的耦合度)
我们按照分离业务,降低耦合度的原则,将代码按以下思路进行拆分:
1、View.vue
打开中国地图
打开美国地图
打开英国地图
export default {
name: "View",
data() {
return {
/**
将地图的业务全部抽离到对应的dialog里面去,View只存放调度业务代码
*/
};
},
methods: {
openChina() {
this.$refs.china && this.$refs.china.openDialog();
},
openUSA() {
this.$refs.usa && this.$refs.usa.openDialog();
},
openUK() {
this.$refs.uk && this.$refs.uk.openDialog();
},
},
};
2、ChinaMapDialog.vue
我是中国地图的弹窗
export default {
name: "ChinaMapDialog",
data() {
return {
// 对中国地图业务逻辑的封装处理 省略
baiduMapVisible: false,
};
},
methods: {
// 对百度地图和谷歌地图的一些业务处理代码 省略
openDialog() {
this.baiduMapVisible = true;
},
closeDialog() {
this.baiduMapVisible = false;
},
},
};
3、由于此处仅仅展示伪代码,且和 ChinaMapDialog.vue 表达的含义一致, 为避免篇幅过长 USAMapDialog.vue 和 UKMapDialog.vue 已省略
2、问题分析
我们通过对这几个弹窗的分析,对刚才的设计进行抽象发现,这里面都有一个共同的部分,那就是我们对 dialog 的操作代码都是可以重用的代码,如果我们能够编写出一个抽象的弹窗,
然后在恰当的时候将其和业务代码进行组合,就可以实现 1+1=2 的效果。
3、设计
由于 Vue 在不改变默认的 mixin 原则(默认也最好不要改变,可能会给后来的维护人员带来困惑)的情况下,如果在混入过程中发生了命名冲突,默认会将方法合并(数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先),因此,mixin 无法改写本来的实现,而我们期望的是,父类提供一个比较抽象的实现,子类继承父类,若子类需要改表这个行为,子类可以重写父类的方法(多态的一种实现)。
因此我们决定使用 vue-class-component 这个库,以类的形式来编写这个抽象弹窗。
import Vu