最近接触到这样一个需求,我需要使用到类似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都一动不动啦!!!然后就可以安安心心自定义弹窗啦~~~~