使用饿了么的select组件遇到的问题

1,283 阅读3分钟

这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战

问题

前几天使用了饿了么的select组件,正常使用是没有问题。但是我们这次需求有了个变更,需要针对select组件的option选项做动态显示,

具体是option选项可以动态添加。

  • 如果select组件只有一个,则正常显示;
  • 如果select组件大于一个,则它下面的option选项的某个需要去掉。

这个需求不难,三下五除二,滴答滴答一下,我就写好了。

用下面这个图举个例子:比如select组件只有一个的时候,则显示所有,如果select组件大于1个,则所有选项需要去掉。

GIF 2021-12-21 11-38-07.gif

  <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'
}],

image.png

可以看到多了一个无匹配数据

为什么会出现这个无匹配数据,网上搜索无果,只能去饿了么源码那里看看咯

分析

node_modules找到element-ui的文件夹,然后,打开packages文件夹,找到select文件夹,里面srcselect.vue就是select组件了。

下面我把流程简单表述一下:

select组件监听visible属性,options没下拉时为false,下拉时为true。select组件有个filteredOptionsCount属性,初始值是0, 然后赋值options的长度。

image.png

下拉的时候,会触发handleQueryChange事件,并传入当前value,在这个事件,会触发option组件的queryChange事件,然后传入value.

image.png

option组件的queryChange事件,会针对value和option的label对比,如果不匹配,则把select组件的filteredOptionsCount属性减一。

image.png

但是会有一个option的label和value相等,所以filteredOptionsCount属性不会为0,一般是1。

我们再来看看无匹配数据的判断条件:

  1. 开始输入筛选(filterable为true)
  2. 有query,也就是有初始value
  3. option长度大于0
  4. filteredOptionsCount 等于0

同时满足这四个条件则会显示无匹配数据。

image.png

这时候可能还会有疑问,filteredOptionsCount正常情况下都会为1,什么情况下会为0?

这时候你要记得我们是在visible-change事件的时候把第一项(所有)删掉了,也就是销毁,然后option组件是有监听beforeDestroy钩子函数的,,所以会触发这个钩子函数。

在这个钩子函数里面会触发select组件的onOptionDestroy方法 image.png

image.png

然后在这里会把filteredOptionsCount减一,导致等于0。所以就触发了无匹配数据

结论

一般不要对option选项做删除操作,建议可以适用disabled属性,禁用就行。

感谢大家的阅读。