el-select滚动分页加载、模糊搜索
大部分情况下使用 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-selectv-model="selectData"v-loadmore="handleScroll"filterableremoteclearable:remote-method="remoteMethod"@clear="clearSelect"><el-optionv-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-itemlabel="会议名称:"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;},
}