大部分情况下使用 el-select 的时候,el-options 中 options 的值都是后端接口给的数据,直接赋值就可以了。但是有的时候数据量比较大,比如几千甚至上万条的时候,如果直接赋值,整个页面的 dom 会被撑爆,不仅请求全量数据接口的时候时间会很久,而且赋值完之后整个页面会非常卡。
解决方案:
我们可以实现一个Vue的自定义指令,每当使用el-select滚动到列表底部的时候就请求下一页数据,来达到下拉滚动加载更多的目的。并将其封装为一个组件,使用时调用父组件传入下拉列表的内容,并在选中数据时回传选中的数据。
1.封装触底自定义指令
src/plugins/select目录下创建 select.js,并在main.js中全局引入
代码主要是实现一个el-select下拉加载的自定义指令v-loadmore:
import Vue from "vue";
export default {}.install = (Vue, options = {}) => {
Vue.directive("loadmore", {
inserted(el, binding) {
// 获取element-ui定义好的scroll盒子
const SELECTDOWN_DOM = el.querySelector(
".el-select-dropdown .el-select-dropdown__wrap"
);
SELECTDOWN_DOM.addEventListener("scroll", function () {
const CONDITION =
this.scrollHeight - this.scrollTop <= this.clientHeight + 2;
if (CONDITION) {
binding.value();
}
});
},
});
};
代码说明:
document.querySelector:querySelector() 方法仅仅返回匹配指定选择器的第一个元素。
Element.scrollHeight:在不使用滚动条的情况下为了适应视口中所用内容所需的最小高度(只读)
Element.scrollTop:获取或设置一个元素的内容垂直滚动的像素数。
Element.clientHeight:读取元素的可见高度(只读)。
元素滚动到底,下面等式返回true,没有则返回false。
警告: 在使用显示比例缩放的系统上,scrollTop可能会提供一个小数。
2.在 mian.js 引入封装好的自定义指令
import loadMore from './plugins/select'
Vue.use(loadMore)
3、创建一个组件LazySelect.vue
<template>
<div>
<el-select
v-model="selectData"
v-loadmore="handleScroll"
filterable
remote
clearable
:remote-method="remoteMethod"
@clear="clearSelect"
>
<el-option
v-for="item in meetList"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
</div>
</template>
<script>
export default {
name: "LazySelect",
props: {
// 外部传入的获取数据的方法
fetchDataMethod: {
type: Function,
required: true,
},
getSelectDataMethod: {
type: Function,
required: true,
},
},
data() {
return {
meetList: [], //案件数据
total: 0, //案件所有总数(接口返回)
dqmeetTotal: 0, //当前案件总数(每次存储的长度)
meetTotal: 0, //案件总数
selectfy: {
page: 0, //当前页码
size: 20, //每页显示条数
},
selectData: null, //选中的案件数据
};
},
watch: {
selectData: {
handler(val) {
let valData = val && val != null ? val.toString() : null;
this.getSelectDataMethod(valData);
},
deep: true,
},
},
created() {
this.getMeetnewlist(); //获取
},
methods: {
handleScroll() {
console.log(this.dqmeetTotal, this.meetTotal);
if (this.meetList.length < this.meetTotal) {
this.getMeetnewlist(); //获取
}
},
// 获取案件
getMeetnewlist() {
this.selectfy.page = this.selectfy.page + 1;
this.fetchDataMethod("", this.selectfy.page, this.selectfy.size).then(
(res) => {
this.meetList = this.meetList.concat(res.rows); //案件信息
this.dqmeetTotal = this.meetList.length; //当前案件总数
this.meetTotal = res.total; //案件所有总数(接口返回)
}
);
},
// 关联案件下拉菜单远程搜索
remoteMethod(val) {
this.fetchDataMethod(val, 1, this.selectfy.size).then((res) => {
this.meetList = res.rows ? res.rows : []; //案件信息
this.dqmeetTotal = this.meetList.length; //当前案件总数
this.meetTotal = res.total; //案件所有总数(接口返回)
});
},
clearSelect() {
this.selectfy.page = 0;
this.meetList = [];
this.getMeetnewlist(); //获取
},
},
};
</script>
<style scoped>
/* 自定义样式(如果需要) */
</style>
4、在页面中使用组件:
html部分:
<el-form-item
label="会议名称:"
prop="meetingId"
v-if="modalType == '1'"
>
<LazySelect
:fetchDataMethod="fetchDataFromServer"
:getSelectDataMethod="getSelectData"
/>
</el-form-item>
js部分:
components: {
LazySelect: () => import("@/components/managementMeeting/LazySelect.vue"),
},
methods(){
//会议名称查询
fetchDataFromServer(query, page, pageSize) {
console.log("query, page, pageSize", query, page, pageSize);
return new Promise((resolve, reject) => {
let param = {
name: query,
pageNum: page,
pageSize: pageSize,
};
// 假设 meetingRecordSelect 是一个返回 Promise 的函数
meetingRecordSelect(param)
.then((response) => {
if (response.code === 200) {
if (response) {
resolve(response); // 返回获取到的数据
} else {
resolve([]); // 如果没有数据,返回空数组
}
} else {
reject(new Error("查询失败,返回错误代码:" + response.code)); // 如果接口返回的 code 不为 200,拒绝 Promise
}
})
.catch((error) => {
reject(error); // 如果请求发生错误,拒绝 Promise
});
});
},
//选中的数据
getSelectData(data) {
this.form.meetingId = data;
},
}