一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
假设有如下list,我们使用 v-for 将其渲染到页面,并且希望在点击不同项时会执行不同的事件。
list:[
{title:'点击执行事件A'},
{title:'点击执行事件B'},
{title:'点击执行事件C'}
]
要实现上述需求,最常见的做法就是为元素绑定 click 事件 handleClick,然后将 title 属性作为参数传入 handleClick 中,接着使用 if-else 来判断要执行的是哪个事件。
<ul>
<li v-for="item in list"
:key="item.title"
@click="handleClick(item.title)">
{{ item.title }}
</li>
</ul>
handleClick(title){
if(title === '点击执行事件A'){
A();
} else if(title === '点击执行事件B'){
B();
} else{
C();
}
}
上面这种方式,虽然能实现需求,但是假如当 title 的值多起来的时候,其可读性就会降低很多,毕竟满屏的 if-else 谁看了都会觉得眼花,为了提高其可读性,我们可以使用另一种方法 switch 语句 来实现需求。
handleClick(titile){
switch(title){
case '点击执行事件A':
A();
break;
case '点击执行事件B':
B();
break;
case '点击执行事件C':
C();
break;
}
}
使用 switch 确实使得代码变得好了那么一丢丢,但是还是不够,当条件多起来的时候,满屏的 case 还是让人看起来有点吃力,而且每个 case 都要带上一个 break,假设有 100 个 case ,那我们就重复写了 100 个 break。
这样不大好,所以我们进一步思考,在上面这个需求中,list 中的元素和元素所对应的事件是一对一的关系,也就是说,list中的第一个元素对应着事件A,第二个元素对应着事件B,第三个元素对应着事件C。我们往跳一层,可以发现,这种关系可以抽象成对象中的键值对 , 以list为例子,我们将每个元素中 title 属性的值作为键名 key,将其对应的事件作为值 value,创建一个对象,进而我们可以将 handleCLick 改为如下形式:
hanldeClick(title){
const methodsTree = {
点击执行事件A:() => { /*事件A逻辑*/ },
点击执行事件B:() => { /*事件B逻辑*/ },
点击执行事件C:() => { /*事件C逻辑*/ },
}
// 执行事件
methodsTree[title] && methodsTree[title]();
}
考虑到会有同值不同键的情况,我们可以把事件抽离出去,将 handleClick 变成下面这样:
hanldeClick(title){
const methodsTree = {
点击执行事件A:this.methodA,
点击执行事件B:this.methodB,
点击执行事件C:this.methodC,
}
// 执行事件
methodsTree[title] && methodsTree[title]();
}
这样子看起来似乎是已经让代码清晰了很多了,但是我们不妨停下来再仔细想想,我们从 if-else 到 switch 再到 methodsTree 是为了干什么? 是为了提高代码的可读性 呀,那什么是可读性? 就是当我们看到list的代码时,就已经能很明确的知道它每个元素所对应的事件了,而不同再跑到 handleClick 中逐个条件的去翻找它们的对应关系。 所以,我们转变个角度,从 list 的代码入手,将其修改成下面这种格式:
list:[
{
title:'点击执行事件A',
methodName:'methodA'
},
{
title:'点击执行事件B',
methodName:'methodB'
},
{
title:'点击执行事件C',
methodName:'methodC'
}
]
然后 handleClick 接收的参数就不再是单单一个 title 属性了,而是整个 item 了,当然,methodA\methodB\methodC 要先定义好。
handleClick(item){
this[item.methodName] && this[item.methodName](); // 执行对应事件
}
到这一步了,代码的可读性已经够强了吧。
补充:
上面的方法都是写在 methods 里面的,这样很不容易管理,我们可以将方法抽离出来写在一个 .js 文件中,然后通过 import 导入,但是这样做的话,handleClick 的代码就要变动一下了:
import * as moduleOne from './moduleOne.js' // 导入方法
handleClick(item){
moduleOne[item.methodName] && moduleOne[item.methodName]().call(this);
}
从上面的代码可以看出,最后使用了 call() 来更改 this 的指向指向当前 vue 实例,为什么调用 methods 中的方法不需要使用 call(this) 呢?有两点原因:
vue中,methods里的方法会被vue通过bind()方法绑定this的指向为当前vue实例,以后就算通过call()和apply()也是无法修改的 ,所以调用methods中的方法无需使用call(this),不然就有点画蛇添足了;- 当方法或者函数写在
export外面时,就需要使用call(this)来获取当前vue实例。
结束,下班!