我有很多的Form表单,在Form表单内又有很多的select选择器,这些选择器的下拉列表都是通过后端的接口传回的数据渲染的,如果每一个Select选择器都使用创建一个组件的话,页面的代码冗余量就会很大,开发的成本以及维护的成本也相对高很多,所以有必要进行封装。
我一开始是先在网上找这方面的文章发现目前的文章都不太适合我的需求,于是自己想办法封装了一个,在这里分享一下思路及代码。
创建RangeSearch.vue
<!--
component:远程搜索下拉列表
time:2022/12/15
1.placeholder(默认为空数组):占位符
示例:
:placeholder="'Please_enter_customer_ID'"
2.SelectData(必传):下拉框数据
此处有有一个重要逻辑,原本这个数据是子组件接收源数据在进行处理,但是这样子无法自适应各种数据的字段,所以使用父组件去进行处理,处理完成在传给子组件
示例:
:SelectData="CustomerIDData"
this.CustomerIDData = CustomerID.data.map((item) => {
return {value : item.CustomerID.toString() , label : item.CustomerID.toString()}
})
还有一个点需要注意,这个方法需要转为字符串格式,所以需要toString()
3.multiple(默认为true):是否多选
示例:
:Ifmultiple=false
4.clearable(默认为false):是否可清空
注意该属性仅适用于单选
示例:
:Ifmultiple=true
-->
<template>
<div class="RangeSearch">
<el-select
v-model="employeesData.transshipmentdepot"
filterable
remote
reserve-keyword
:multiple=Ifmultiple
:clearable=Isclearable
:placeholder="$t(placeholder)"
:remote-method="transshipmentdepotremoteMethod"
:focus="transshipmentdepotremoteMethod"
:loading="loading"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
</template>
<script>
export default {
data(){
return{
options: [],
value: [],
list: [],
loading: false,
employeesData:{
transshipmentdepot:'',
},
data:[], //暂存下拉数据,用于当输入为空时显示
multipleSelection:'', //是否多选
}
},
props:{
placeholder:{
default(){
return [];
}
},
SelectData:{
default(){
return [];
}
},
Ifmultiple:{
type: Boolean,
default: true
},
Isclearable:{
type: Boolean,
default: false
},
},
methods:{
transshipmentdepotremoteMethod(query) {
if (query !== '') {
this.loading = true;
setTimeout(() => {
this.loading = false;
this.options = this.list.filter(item => {
return item.label.toLowerCase()
.indexOf(query.toLowerCase()) > -1;
});
}, 200);
} else {
this.options = this.data
}
}
},
mounted(){
},
watch:{
SelectData:function(newVal){
this.options = newVal
this.data = newVal
this.list = newVal
}
},
}
</script>
<style>
</style>
为了启用远程搜索,需要将
filterable
和remote
设置为true,同时传入一个remote-method
。remote-method
为一个Function
,它会在输入值发生变化时调用,参数为当前输入值。需要注意的是,如果el-option
是通过v-for指令渲染出来的,此时需要为el-option
添加key属性,且其值需具有唯一性。
filterable:是否为可搜索
remote:是否为可远程搜索
reserve-keyword:多选且可搜索时,是否在选中一个选项后保留当前的搜索关键词
multiple:是否多选
clearable:是否可以清空选项
placeholder:占位符
remote-method:远程搜索方法
focus:当 input 获得焦点时触发
loading:是否正在从远程获取数据
以上这些是官方文档说明的我就不详细讲解了,主要讲讲我这里的封装思路
placeholder:占位符
我这里是"$t(placeholder)“,因为我用的是中英切换的语法,可以直接"placeholder”)
SelectData:下拉框数据
这个数据是必传的,这里的SelectData代表已经处理好的数据直接渲染在下拉列表中,简单的说就是我们需要渲染的数据,至于源数据如何变成我们需要渲染的数据这个操作是在调用这个组件的时候(父组件)中完成的,这里只渲染数据而不是处理数据在渲染数据。
为什么要这样子做,因为很多地方可能会用到,他们的源数据是不一样的,然后需要渲染的字段也不一样,比如说我这里渲染客户IDitem.CustomerID
,然后在其他地方我可能要渲染仓库IDitem.WarehouseID
,这样子的话如果让组件来处理源数据。
在return的时候item.CustomerID.toString()
,item.CustomerID.toString()
这里就会出现问题,因为CustomerID
是我客户ID渲染时需要的ID字段名,那我要渲染仓库的时候需要WarehouseID
就无法自适应到了,也就是说这里的item.CustomerID.toString()
是写死的,因为完全不知道源数据的字段是什么,如果我们在调用组件时直接处理好源数据,传过来都是统一格式的数据,全部使用统一的字段遍可以达到使用的目的,但是这样的话使用成本会稍微高点,但是我目前也想不到更加好的实现方法,后续如果有更好的实现方法还会在分享出来。
这里拿到SelectData
之后用watch监听器去监听数据变化,将最新传入的数据赋值给组件
options :下拉列表数据
data:这个data是我自己创建的,目的是一开始点击或者当输入为空时,Element的做法是将options
赋值为空,但是我想要在为空时展示所有的数据,所有这里创建了一个data,当输入的数据为空时则将data传给options
,就达到了我想要的目的。
list:处理好的下拉列表数据
<template>
<div>
<RangeSearch
:placeholder="'Please_enter_User_Stock'"
:SelectData="this.warehouseData"
:multiple=false
:clearable=false
></RangeSearch>
</div>
</template>
<script>
import RangeSearch from '@/components/RangeSearch.vue'
mounted(){
this.warehouseData = warehouse.data.map((item) => {
return {value : item.StockID , label : item.Name}
})
}
</script>
//使用示例:
:placeholder="'Please_enter_customer_ID'"
因为使用组件需求的不同,其占位符也不同,通过在页面中使用时将placeholder
传入拿到数据,这样子就可以做到同一个组件不同占位符。
//使用示例:
:SelectData="CustomerIDData"
this.CustomerIDData = CustomerID.data.map((item) => {
return {value : item.CustomerID.toString() , label : item.CustomerID.toString()}
})
此处有有一个重要逻辑,原本这个数据是子组件接收源数据在进行处理,但是这样子无法自适应各种数据的字段,所以使用父组件去进行处理,处理完成在传给子组件
这里还有一个点需要注意为什么要toString()
一下,因为element组件的原因只支持字符转的格式,当传入的未数组以及对象时则会出错,所以这里建议toSring()
一下。
this.CustomerIDData
:需要渲染的数据
CustomerID.data
:源数据
:SelectData="CustomerIDData"
:注意放这个的位置是在使用这个组件的地方写的,剩下的是在父组件的生命周期函数mounted
中写的。
//使用示例:
:Ifmultiple=false
这个很简单理解就是是否为多选(True:是,False:否)
//使用示例:
:Ifmultiple=tr
这个也很好理解就是是否为可清空(True:是,False:否)
但是需要注意该属性仅适用于单选