当提交的表单Form需要填某个实体的外键ID时,当然不可能使用el-input组件,这个适合提交字符串,然后用户又不可能记住某个引用的外键ID,这时候使用el-select还是必要的。
el-select组件一般都作为下拉选择框使用,但仅在数据量少时,比较实用,比如性别的选择:男女。
但当需要选择的数据成千上万时,就不太适用了(不可能拉一长串数据)。这就需要对其进行再改造封装。
上述实现了两个效果,一个是通过远程搜索数据,一个是打开对话框筛选数据。
<template>
<div class="custom-select">
<el-select v-model="innerValue" multiple filterable remote reserve-keyword :remote-method="remoteMethod"
:multiple-limit="limit" :loading="loading" @change="change" tag-type="">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<div class="custom-icon">
<div class="custom-icon__wrapper">
<font-awesome-icon icon="search" @click="clickMethod" />
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, onMounted, computed, watch } from 'vue'
import { queryBill } from '@/api/lcdp/bill.js'
const props = defineProps({
//远程搜索的方法
searchMethod: {
type: Function,
default: () => { }
},
//显示label标签的方法
showMethod: {
type: Function,
default: () => { }
},
//多选限制数量
limit: {
type: Number,
default: 1
},
//父组件传递的值
value: {
type: Number || Array || String,
defalt: 1
}
})
const options = ref<ListItem[]>([])
const innerValue = ref<Number[] | String[]>([])
const loading = ref(false)
interface ListItem {
value: string
label: string
}
// 监听父组件传递的值的变化
watch(
() => props.value,
async () => {
if (props.value == null) {
innerValue.value = []
}
if (typeof props.value === 'number') {
innerValue.value = [props.value]
const response = await props.showMethod(innerValue.value)
options.value = response.data
}
}
)
// 初始化父组件传递的值
onMounted(async () => {
if (props.value == null) {
innerValue.value = []
}
if (typeof props.value === 'number') {
innerValue.value = [props.value]
const response = await props.showMethod(innerValue.value)
options.value = response.data
}
})
/**
* 通过关键词查询选择框列表
* @param query 查询参数
*/
const remoteMethod = async (query: string) => {
if (query) {
loading.value = true
const response = await props.searchMethod({ q: query })
loading.value = false
options.value = response.data
} else {
options.value = []
}
}
//...省略开启对话框逻辑
</script>
<style lang="scss" scoped>
//将阴影和圆角去掉
::v-deep(.el-input__wrapper) {
border-radius: 0;
box-shadow: 0 0 0 0;
}
//给边框添加阴影,并调整搜索框位置
.custom-select {
display: inline-block;
box-shadow: 0 0 0 1px var(--el-input-border-color, var(--el-border-color));
.custom-icon {
display: inline-block;
color: var(--el-input-icon-color, var(--el-text-color-placeholder));
vertical-align: middle;
cursor: pointer;
.custom-icon__wrapper {
padding: 1px 11px;
}
}
}
</style>
思路是在el-select后边再加一个icon图标,然后添加上阴影,并隐藏suffix-icon图标和自带的阴影,伪装成一个合体的组件。
这个组件我折腾了好久,之前想用自带的suffix-icon实现,谁知道图标Component是给属性赋值的,并不是子组件。不能给el-select传递数据,所以失败了。。。
所以想到了这么一个方法。
最终这样一个支持远程搜索,还能打开对话框分页查询数据的组件就封装好了。