需求: 项目中有个select框,后端返回的数据过多。直接使用则会出现点击select后进行选择发现十分卡顿,影响体验。
解决: 利用先获取数据,从中截取一部分,根据下拉框的滚动实现无线加载。
须引入loadsh 用于对下拉操作进行防抖操作
<template>
<div>
<a-select
v-bind="$attrs"
v-on="$listeners"
:style="{ width: `${width}` }"
:placeholder="placeholder"
:value="value"
:showSearch="true"
:allowClear="true"
:dropdownMatchSelectWidth="false"
:getPopupContainer="(triggerNode) => triggerNode.parentNode"
:token-separators="separators"
option-filter-prop="children"
@search="handlerFilterOption"
@popupScroll="handlerScroll"
@blur="handlerBlur"
@dropdownVisibleChange="handlerDropdown"
>
<a-select-option
v-for="(item, index) in uniqFilterSelectOptions"
:key="index"
:value="item.value"
>{{ item.label }}</a-select-option>
</a-select>
</div>
</template>
<script>
export default {
name: "x-select",
model: {
prop: "value",
event: "change",
},
props: {
// 父组件通过v-model实现父子组件数据选择同步
value: {
type: [Array, Number, String],
default: undefined,
},
// 下拉列表数据
options: {
type: Array,
default: () => [],
},
width: {
type: [Number, String],
default: () => "100%",
},
// 初始化和每次滚动显示的最大条数
maxShowStrips: {
type: Number,
default: 15,
},
placeholder: {
type: String,
default: "请选择",
},
},
data() {
return {
separators: [";", ",", "/\n/", " "],
userSerach: "", // 用户搜索时的内容
filterOptions: [], // 过滤用户输入后的option
selected: undefined, // 选择的数据
};
},
computed: {
// 避免重复插入截取的数据
uniqFilterSelectOptions() {
let { filterOptions = [] } = this;
let optionsList = [];
return filterOptions.filter((item) => {
let { value } = item || {};
if (optionsList.includes(value)) {
return false;
} else {
optionsList.push(value);
return true;
}
});
},
},
methods: {
// 得到下拉列表的数据
getSelectOptions() {
let { userSerach = "", options = [], maxShowStrips = 15 } = this;
if (!Array.isArray(options)) return;
let tempFilterOptions = userSerach
? options.filter((item) => {
let { label = "" } = item || {};
return label && label.indexOf(userSerach) !== -1;
})
: options;
tempFilterOptions = tempFilterOptions.length > maxShowStrips
? tempFilterOptions.slice(0, maxShowStrips)
: tempFilterOptions
this.filterOptions = tempFilterOptions;
},
// 滚动条滚动,无限拼接数据
handlerScroll: _.debounce(function () {
let { options = [], maxShowStrips = 15, filterOptions = [] } = this;
let currindex = filterOptions.length;
let allIndex = options.length;
let nextPageIndex = currindex + maxShowStrips;
let newFilterOptions =
nextPageIndex > allIndex
? options.slice(currindex, allIndex)
: options.slice(currindex, nextPageIndex);
this.filterOptions = filterOptions.concat(newFilterOptions);
}, 200),
// 用户改变搜索条件
handlerFilterOption(value) {
this.userSerach = value || "";
this.getSelectOptions();
},
// 用户取消选中
handlerBlur() {
this.userSerach = "";
this.getSelectOptions();
},
// 展开下拉菜单的回调
handlerDropdown(flag) {
if (flag) this.getSelectOptions();
},
},
watch: {
options: {
handler() {
this.getSelectOptions();
},
immediate: true,
deep: true,
},
},
};
</script>
使用例子 可多选
<template>
<x-select
v-model="value"
:options="List"
@change='handleChange'
placeholder="请选择.."
/>
<!-- 多选则添加 mode="multiple" -->
</template>
<script>
export default {
components: {
x-select: () => import("./xSelect"),
},
data() {
return {
value: undefined,
List: [],
};
},
methods: {
handleChange(value){
console.log(value);
}
},
};
</script>