说在前面
为了方便日常开发,我们经常会封装一些常用的组件,方便系统中各个模块使用,但是引用的地方多了,由于每个模块可能有自己的特殊使用场景,使用过程中可能出现一些不可预料的问题,今天我们来学习利用面向对象中多态的思想来更好的封装一个组件。
多态
多态通俗点来说,就是给不同的对象发送同一个消息,这些对象会根据这个消息分别给出不同的反馈。
下面用代码来简单描述下这一过程:
var makeSound = function (animal) {
animal.sound()
}
var Duck = function(){}
Duck.prototype.sound = function() {
console.log('嘎嘎嘎')
}
var Dog = function(){}
Dog.prototype.sound = function() {
console.log('汪汪汪')
}
makeSound(new Dog)
makeSound(new Dock)
对于这个例子来说,只要对象自带sound()方法,可以表明自己的“身份”,我们永远不需要改动makeSound()
方法。
如果不使用多态,许多人先入为主的做法可能是在makeSound
方法中使用if..else..
来维护不同的动物,类似:
if (animal instanceof Duck) {
console.log('嘎嘎嘎')
}
从封装的角度来说,我们所希望的肯定是能适配更多的情况,而不是出现一种新情况就来修改封装的组件本身,后者很明显会导致更多不可预期的错误,因为组件应用的很多,随意改动任何一行代码都可能导致其他组件异常。
实际应用
现在要封装一个目录树组件,最基础的功能就是目录树的展示,通过前期的调研,了解到不同模块需要对目录树返回的数据进行过滤,有的模块需要展示不同的层级,有的模块需要过滤特定条件下的目录树节点,下面我们按照多态的思想,将可变的部分封装一下,从而对封装的组件进行完善。
tree组件:
<html>
<el-tree :data="treeData"></el-tree>
</html>
<script>
name: 'tree',
data() {
return {
treeData: []
}
},
props: {
doNodeFilter: { // 接收自定义过滤节点方法,如果存在,则执行,默认null
type: Function,
default: null
}
},
methods: {
getTreeNode() {
getTreeNodeAjax().then(res => {
if (this.doNodeFilter) {
this.treeData = this.doNodeFilter(res.data)
} else {
this.treeData = res.data
}
})
}
},
mounted () {
this.getTreeNode()
}
</script>
app:
<tree :doNodeFilter="doNodeFilter"></tree>
<script>
name: 'app1',
methods: {
doNodeFilter(data) {
// 实现自己希望过滤的算法逻辑
}
}
</script>
上述代码只是一个大致思路,部分代码不是很完整,但是不影响阅读,如此实现,每个使用tree
组件的地方都可以定义自己的过滤方法,如果不定义,则默认返回所有节点。同理比如点击数节点希望返回某些信息也可以利用此方法。
总的来说,组件不做任何的“决策”,引用组件的模块通过传入定制化方法或参数来实现自己的需求。
说到最后
以上。