如何禁止el-select下拉框弹出?

17 阅读3分钟

最近接触到这样一个需求,我需要使用到类似el-select的功能,但是无需弹出原始的下拉框,我需要的是点击整个框,弹一个弹窗,弹窗里面有查询表单、查询列表,还可以分页,选中某一项后,回显到el-select上。

需求明了了,我一开始想到的是怎么去隐藏下拉框,多番努力后无果......无奈全网搜索,不出半刻,大悦!!!感谢万能的IT贡献者们,你们真乃大神也!!!下面是学习到的最简单粗暴的办法。

<template>
    <el-select
        ref="selectRef"
        v-model="value"
        collapse-tags-tooltip
        placeholder="Select"
        style="width: 240px"
        @visible-change="visibleChange"
    >
        <el-option
            v-for="item in options"
            :key="item.value"
            :label="item.label"
            :value="item.value"
        />
    </el-select>
</template>

<script setup>
    import { ref, nextTick } from 'vue';
    const value = ref('2');
    const selectRef = ref(null);
    const options = ref([
        { value: '1', label: '湖北' },
        { value: '2', label: '湖南' },
        { value: '3', label: '河北' },
        { value: '4', label: '山西' },
        { value: '5', label: '山东' },
    ]);
    const visibleChange = () => {
        nextTick(() => {
            const currentSelect = selectRef.value;
            if (currentSelect) {
                currentSelect.blur();
            }
        });
    };
</script>



对没错,就是 visibleChange 这个方法里面的代码起的作用,让弹窗将要打开的时候,在nextTick里面失去焦点~

但是,问题来了,当我喜气洋洋地将如上方式用在我的项目中时,意外发生了......我上面没讲完,我是要运用到表格里面的默认插槽里面,那么发生什么意外了呢?当我有多行表格时,甚至表格是动态新增时,永远只有最后一行的表格里面插的select打不开下拉框,前面几行的下拉框依然可以打开,请看如下有问题的代码:
```js
<template>
  <el-table :data="tableData" border style="width: 100%">
    <el-table-column prop="date" label="Date" width="180" />
    <el-table-column prop="name" label="Name" width="180" />
    <el-table-column prop="address" label="Address">
      <template #default="{row}">
        <el-select
          ref="selectRef"
          v-model="row.address"
          collapse-tags-tooltip
          placeholder="Select"
          style="width: 240px"
          @visible-change="visibleChange"
        >
          <el-option
            v-for="item in options"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
       </template>
    </el-table-column>
  </el-table>
</template>
<script setup>
import {ref, nextTick} from 'vue'
const selectRef = ref(null)
const tableData = [
  {
    date: '2016-05-03',
    name: 'Tom',
    address: '1',
  },
  {
    date: '2016-05-02',
    name: 'Lucy',
    address: '2',
  },
  {
    date: '2016-05-04',
    name: 'Lily',
    address: '3',
  },
  {
    date: '2016-05-01',
    name: 'Anna',
    address: '5',
  },
]
const options = [
  {
    value: '1',
    label: '湖北',
  },
  {
    value: '2',
    label: '湖南',
  },
  {
    value: '3',
    label: '河北',
  },
  {
    value: '4',
    label: '山西',
  },
  {
    value: '5',
    label: '山东',
  },
]
const visibleChange = () => {
  nextTick(()=>{
    const currentSelect = selectRef.value;
    if (currentSelect) {
      currentSelect.blur();
    }
  })
}
</script>

侥幸的我,看测试也没提出来,因为后续点击加了个弹窗,把页面挡住了一大半,他自然是很难注意到。问题不大,我就暂且放到了一边,过了些时日,终于有时间来想这个问题。思忖半天,才意识到,我的 ref 有问题,表格每一行都有 select, 每一个 select 的 ref 命名都是一样的了,所以无论我怎么点击 select, 永远只有最后一个生效了,真想此刻来一个捂脸的表情......

所以,我需要动态创建每一个 select 的 ref,请移步如下代码查看:

<template>
  <el-table :data="tableData" border style="width: 100%">
    <el-table-column prop="date" label="Date" width="180" />
    <el-table-column prop="name" label="Name" width="180" />
    <el-table-column prop="address" label="Address">
      <template #default="{row, $index}">
        <el-select
          :ref="
              (el) => {
                  if (el) selectRefs[$index] = el;
              }
          "
          v-model="row.address"
          collapse-tags-tooltip
          placeholder="Select"
          style="width: 240px"
          @visible-change="(visible) => visibleChange(visible, $index)"
        >
          <el-option
            v-for="item in options"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
      </template>
    </el-table-column>
  </el-table>
</template>
<script setup>
import {ref, nextTick, onBeforeUpdate} from 'vue'
// 定义数组refs
const selectRefs = ref([]);
const tableData = [
  {
    date: '2016-05-03',
    name: 'Tom',
    address: '1',
  },
  {
    date: '2016-05-02',
    name: 'Lucy',
    address: '2',
  },
  {
    date: '2016-05-04',
    name: 'Lily',
    address: '3',
  },
  {
    date: '2016-05-01',
    name: 'Anna',
    address: '5',
  },
]
const options = [
  {
    value: '1',
    label: '湖北',
  },
  {
    value: '2',
    label: '湖南',
  },
  {
    value: '3',
    label: '河北',
  },
  {
    value: '4',
    label: '山西',
  },
  {
    value: '5',
    label: '山东',
  },
]
// 下拉框显示时 - 只处理当前行的select
const visibleChange = (visible, index) => {
  // 下拉框没打开,就不做处理
  if(!visible) return
  nextTick(() => {
      const currentSelect = selectRefs.value[index];
      if (currentSelect) {
          currentSelect.blur();
      }
  });
}
// 在组件更新前清空refs数组,防止内存泄漏 
onBeforeUpdate(() => { 
  selectRefs.value = []; 
});
</script>

如此一来,每个select都一动不动啦!!!然后就可以安安心心自定义弹窗啦~~~~