这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战
问题
前几天使用了饿了么的select组件,正常使用是没有问题。但是我们这次需求有了个变更,需要针对select组件的option选项做动态显示,
具体是option选项可以动态添加。
- 如果select组件只有一个,则正常显示;
- 如果select组件大于一个,则它下面的option选项的某个需要去掉。
这个需求不难,三下五除二,滴答滴答一下,我就写好了。
用下面这个图举个例子:比如select组件只有一个的时候,则显示所有,如果select组件大于1个,则所有选项需要去掉。
<div id="app">
<el-button type="primary" @click="add">添加</el-button>
<div v-for="(item, i) in valArr" :key="i">
<el-select v-model="item.value" placeholder="请选择" filterable @visible-change="visibleChange">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
<el-button @click="deleteSelect(i)">删除</el-button>
</div>
</div>
var Main = {
data () {
return {
valArr: [{
value: ''
}],
options: [{
value: 'all',
label: '所有'
}, {
value: '选项1',
label: '黄金糕'
}, {
value: '选项2',
label: '双皮奶'
}, {
value: '选项3',
label: '蚵仔煎'
}, {
value: '选项4',
label: '龙须面'
}, {
value: '选项5',
label: '北京烤鸭'
}]
}
},
methods: {
add () {
this.valArr.push({
value: ''
})
},
deleteSelect (i) {
this.valArr.splice(i, 1)
},
visibleChange (status) {
if (status) {
// 大于1并且有所有时则需要删除所有
if (this.valArr.length > 1 && this.options[0].value === 'all') {
this.options.shift()
}
// 小于等于1并且没有所有时则需要加上所有
if (this.valArr.length <= 1 && this.options[0].value !== 'all') {
this.options.unshift({
value: 'all',
label: '所有'
})
}
}
}
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
跟valueArr有关
但是问题来了,如果我的valArr本身有值的且长度大于1,就会有问题。
valArr: [{
value: '选项1'
}, {
value: '选项2'
}],
可以看到多了一个无匹配数据。
为什么会出现这个无匹配数据,网上搜索无果,只能去饿了么源码那里看看咯
分析
在node_modules找到element-ui的文件夹,然后,打开packages文件夹,找到select文件夹,里面src的select.vue就是select组件了。
下面我把流程简单表述一下:
select组件监听visible属性,options没下拉时为false,下拉时为true。select组件有个filteredOptionsCount属性,初始值是0, 然后赋值options的长度。
下拉的时候,会触发handleQueryChange事件,并传入当前value,在这个事件,会触发option组件的queryChange事件,然后传入value.
option组件的queryChange事件,会针对value和option的label对比,如果不匹配,则把select组件的filteredOptionsCount属性减一。
但是会有一个option的label和value相等,所以filteredOptionsCount属性不会为0,一般是1。
我们再来看看无匹配数据的判断条件:
- 开始输入筛选(filterable为true)
- 有query,也就是有初始value
- option长度大于0
- filteredOptionsCount 等于0
同时满足这四个条件则会显示无匹配数据。
这时候可能还会有疑问,filteredOptionsCount正常情况下都会为1,什么情况下会为0?
这时候你要记得我们是在visible-change事件的时候把第一项(所有)删掉了,也就是销毁,然后option组件是有监听beforeDestroy钩子函数的,,所以会触发这个钩子函数。
在这个钩子函数里面会触发select组件的onOptionDestroy方法
然后在这里会把filteredOptionsCount减一,导致等于0。所以就触发了无匹配数据。
结论
一般不要对option选项做删除操作,建议可以适用disabled属性,禁用就行。
感谢大家的阅读。