element组件当数据量过大会出现卡顿明显的现象
通过滚动显示更多数据解决卡顿问题
el-select封装
// 控件名称 LargeDataSearchSelect
const debounce = (fun, delay = 500) => {
let timer = null;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fun.apply(this, args);
}, delay);
};
};
// 数字 字符串 function是不需要拷贝的
const deepClone = (value) => {
if (value == null) return value;
if (typeof value !== "object") return value;
if (value instanceof RegExp) return new RegExp(value);
if (value instanceof Date) return new Date(value);
// 我要判断 value 是对象还是数组 如果是对象 就产生对象 是数组就产生数组
let obj = new value.constructor();
for (let key in value) {
obj[key] = deepClone(value[key]); // 看一看当前的值是不是一个对象
}
return obj;
};
export default {
name: "LargeDataSearchSelect",
directives: {
"el-select-loadmore": {
bind(el, binding) {
// 获取element-ui定义好的scroll盒子
const SELECTWRAP_DOM = el.querySelector(
".el-select-dropdown .el-select-dropdown__wrap"
);
SELECTWRAP_DOM.addEventListener("scroll", function () {
/**
* scrollHeight 获取元素内容高度(只读)
* scrollTop 获取或者设置元素的偏移值,常用于, 计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.
* clientHeight 读取元素的可见高度(只读)
* 如果元素滚动到底, 下面等式返回true, 没有则返回false:
* ele.scrollHeight - ele.scrollTop === ele.clientHeight;
*/
const condition =
this.scrollHeight - this.scrollTop <= this.clientHeight;
if (condition) binding.value();
});
},
},
},
props: {
selectProps: {
type: Object,
default: () => {
return {
options: [],
rangeNumber: 10,
};
},
require: true,
},
value: {
type: String,
default: "",
},
},
data() {
return {
selectValue: "",
rangeNumber: this.selectProps.rangeNumber || 10,
options: [],
originalData: [],
};
},
watch: {
value: {
handler(newVal) {
this.selectValue = newVal;
},
deep: true,
immediate: true,
},
},
model: {
event: "updateChange",
},
mounted() {
this.$nextTick(() => {
this.originalData = this.options = deepClone(this.selectProps.options);
});
},
methods: {
loadMore(n) {
if (n < 8) this.rangeNumber = 10;
return () => (this.rangeNumber += 5); // 每次滚动到底部可以新增条数 可自定义
},
handleGlobalIdFilter: debounce(function (query) {
this.selectValue = query;
if (query) {
let newOption = this.originalData.filter((item) =>
item[this.selectProps.label || "label"].includes(query)
);
this.options = newOption.length ? newOption : this.originalData
} else {
this.options = this.originalData;
}
}, 500),
selectBlur() {
this.selectValue = this.value
this.options = this.originalData
},
selectChange() {
this.$emit("updateChange", this.selectValue);
this.options = this.originalData;
},
},
render() {
return (
<el-select
{...this.$attrs}
v-model={this.selectValue}
placeholder={this.selectProps.placeholder || "请选择"}
clearable
filterable
filter-method={this.handleGlobalIdFilter}
onBlur={this.selectBlur}
onChange={this.selectChange}
v-el-select-loadmore:rangeNumber={this.loadMore(this.rangeNumber)}
>
{this.options.slice(0, this.rangeNumber).map((item, index) => {
return (
<el-option
key={index}
label={item[this.selectProps.label || "label"]}
value={item[this.selectProps.value || "value"]}
></el-option>
);
})}
</el-select>
);
},
};
控件使用
<template>
<div class="select">
<div>可搜索的选择框</div>
<LargeDataSearchSelect
v-model="form.data"
:selectProps.sync="selectProps"
@updateChange="updateChange"
/>
<el-button @click="getValue">按钮</el-button>
</div>
</template>
<script>
import LargeDataSearchSelect from "@/components/LargeDataSearchSelect";
export default {
name: "SelectView",
components: { LargeDataSearchSelect },
data() {
return {
form: {
data: "",
},
selectProps: {
options: [],
rangeNumber: 10,
// label: "nihao",
// value: "nihao",
// placeholder: "请选择下拉列表",
},
};
},
mounted() {
this.getSelectData();
},
methods: {
updateChange() {
console.log("你好");
},
// 生成一万条数据
getSelectData() {
let selectData = [];
for (let i = 0; i < 10000; i++) {
selectData.push({
value: `${i}`,
label: `备选项 ${i}`,
});
}
this.selectProps.options = this.options.concat(selectData);
},
},
};
</script>