一个el-select同时支持单选和多选

110 阅读2分钟

背景

常规的下拉框,要么是单选、要么是多选、要么是级联选择。

但是,这些都只是常规的,你永远不知道产品经理是不是常规的!

现在他有个需求,需要做一个下拉框,叫“隐患等级”,里面的选项如下:

image.png

现在他想除了全部不支持多选,其他项都支持多选。

我翻译过来就是:

  • 点击全部,清空其他选择配【看起来是单选了】
  • 点击其他项,如果包含全部这项,则清除全部这项【符合他的需求,全部项不能多选】

实现过程

假设我声明了一个数组、如下所示:

dangerLevelOptions: [
  { value: '', label: '全部', },
  { value: '1', label: '缺陷', },
  { value: '2', label: '一般隐患', },
  { value: '3', label: '较大隐患', },
  { value: '4', label: '重大隐患', },
  { value: '5', label: '特别重大隐患', },
],

同时写了下拉框,代码如下

<el-form-item label="隐患等级">
  <el-select
    v-model="searchParams.dangerLevel"
    placeholder="隐患等级"
    multiple
    collapse-tags
    style="width: 175px;"
    @change="changeLevel"
  >
    <el-option
      v-for="item in dangerLevelOptions"
      :key="item.value"
      :value="item.value"
      :label="item.label"
    />
  </el-select>
</el-form-item>

接下来就是监听searchParams.dangerLevel值了,主要在changeLevel方法里处理。

失败一

一开始我在changeLevel方法里监听,我通过判断值是否包含''来判断是否选择了全部

 changeLevel(value) {
   if (value.includes('')) {
    // 如果选择了“全部”,则清空其他选项
     this.searchParams.dangerLevel = [''];
   } else {
    // 如果没有选择“全部”,则移除“全部”
     this.searchParams.dangerLevel = value.filter(item => item !== '');
   }
}

但是我发现,如果一开始你选择了“全部”,那么就无法选择其他项了,因为searchParams.dangerLevel值始终被置为['']

失败二

后来我就想在watch里监听新旧值的变化、来判断是否选择了全部

watch: {
  'searchParams.dangerLevel': {
    handler(newVal, oldVal) {
      if (newVal.includes('') && !oldVal.includes('')) {
        // 如果新值包含“全部”而旧值不包含“全部”,则清空其他选项【说明点击了全部】
        this.searchParams.dangerLevel = [''];
      } else if (newVal.includes('') && oldVal.includes('')) {
        // 如果新值和旧值都包含“全部”,则清除全部【说明原来是全部,又点击其他项】
        this.searchParams.dangerLevel = newVal.filter(item => item !== '');
      }
    },
    deep: true
  }
},

但是该方法会触发多次,因为你多次改变值了,且可能存在未知的情况,所以该方法也放弃了。

方法三

正当我准备找产品经理打架时,我想先冷静一下,于是我又好好观察了这个下拉框,我发现当前选择的项是数组的最后一项

image.png

于是我灵光一现,决定不去打架了,我只需要判断最后一项是否为''就行了。

  • 如果是,把dangerLevel设置为值:['']
  • 如果不是,则把dangerLevel数组清除''

最终代码如下:

changeLevel(value) {
  // 当前点击的是value数组的最后一项,判断最后一项是否为“全部”,
  // 如果是,则清空其他选项
  // 如果不是,则清除全部
  if (value[value.length - 1] === '') {
    this.searchParams.dangerLevel = [''];
  } else if (value[value.length - 1] !== '') {
    this.searchParams.dangerLevel = value.filter(item => item !=='');
  }
}

总结

东西倒是不难,但是一开始做非常规的还是很抵触的!