问题描述
先看看Select组件的意思:
简单来说,就是下拉选择,可以多选可以单选。如果是多选,绑定的数据就是数组,否则就是单个数据。
有个需求,在Vue中使用Select组件,支持多选,选择某一项,使它与其他项互斥。也就是说,假设这一项叫A,选择A时就必须移除选择的其他选项,而选择其他选项时可以多选不受限制。
本文将使用简单的伪代码描述逻辑,并不是直接就能用的代码。
代码实现
先给出一部分JS代码:
data(){
return {
// Select绑定的数组
select_list: [],
// 选项数组
options_list: ['A', '选项2', '选项3', '选项4', '选项5']
}
}
使用Select组件:
<Select v-model="select_list" multiple>
<Option v-for="item in options_list" :value="item" :key="item"></Option>
</Select>
逻辑就是这样,现在来实现需求。当选择A的时候,需要移除其他选项,只保留A。
很容易想到使用watch实现这个逻辑,即用watch监视select_list,当选择了A时就移除其他选项,只保留A。
不妨试试,逻辑如下:
watch: {
select_list: {
handler(newVal) {
console.log('执行');
if (newVal.indexOf("A") > -1) {
this.select_list = newVal.filter((item) => item == "A");
}
},
deep: true,
},
},
看上去很完美。注意,这里并没有判断oldVal中是否含有A,需要另外处理,但由于这不是这里的重点所以不多说。
执行起来发现,虽然在点击A的时候,似乎可以正常把其他数据移走,但会出现这么个情况:
这仅仅是点击了一次A!
原因很简单,watch每次监视到select_list的变化就会执行,执行handler的时候修改了select_list,于是再次监视到selct_list的变化,再次触发执行,如此周而复始。虽然在UI上似乎看不出问题,但进行了大量的运算,消耗了性能。
说到底,在监视中修改被监视的数据,会导致无限地触发下去。不过,当然可以使用其他办法阻止下一次触发,但我觉得这样并不好。
不如这样,直接在Option上添加click事件监听函数:
<Select v-model="select_list" multiple>
<Option v-for="item in options_list" :value="item" :key="item" @click="add(item)"></Option>
</Select>
这样,在add中判断item的值是不是A。如果是A,则修改select_list,再做其他的工作,就更容易了。注意,这里需要在click后面添加.native,因为Option是一个组件,不是普通标签。