el-select懒加载滚动触底懒加载
直接复制封装组件使用
代码:
<template>
<el-select
:disabled="disabled"
v-model="selectValue"
v-loadmore="loadMore"
@focus="focus"
@clear="clear"
filterable
:placeholder="placeholder"
remote
:filter-method="handleSearch"
:loading="loading"
@change="selectChange"
clearable
v-bind="$attrs"
v-on="$listeners"
>
<el-option
v-for="option in data"
:label="option[dictLabel]"
:value="option[dictValue]"
:key="option.value"
>
<span style="float: left">{{ option[dictLabel] }}</span>
<span
v-if="dictRight"
style="float: right; color: #8492a6; font-size: 13px"
>{{ option[dictRight] }}</span
>
</el-option>
<!-- 此处加载中的value可以随便设置,只要不与其他数据重复即可 -->
<el-option
v-if="!hasMore"
disabled
label="加载完毕..."
value="-1"
></el-option>
</el-select>
</template>
<script>
export default {
props: {
disabled: {
type: Boolean,
default: false,
},
value: {
type: Number,
default: null,
},
placeholder: {
type: String,
default: "请选择",
},
dictRight: {
type: String,
default: null,
},
dictLabel: {
type: String,
default: "label",
},
dictValue: {
type: String,
default: "value",
},
// 查询属性名
selectArr: {
type: String,
default: "name",
},
// 响应数据的属性名
responseValue: {
type: String,
default: "rows",
},
// 调用页数的接口
request: {
type: Function,
default: () => {},
},
// 传入的页距
pageSize: {
type: [Number, String],
default: 10,
},
},
directives: {
// 这里实现一个组件内部的自定义指令
loadmore: {
// 指令的定义
bind(el, binding) {
const SELECTWRAP = el.querySelector(
".el-select-dropdown .el-select-dropdown__wrap"
);
if (!SELECTWRAP) {
throw new Error('获取不到"el-select-dropdown__wrap"节点');
}
SELECTWRAP.addEventListener("scroll", () => {
// scrollTop 这里可能因为浏览器缩放存在小数点的情况,导致了滚动到底部时
// scrollHeight 减去滚动到底部时的scrollTop ,依然大于clientHeight 导致无法请求更多数据
// 这里将scrollTop向上取整 保证滚到底部时,触发调用
const CONDITION =
SELECTWRAP.scrollHeight - Math.ceil(SELECTWRAP.scrollTop) <=
SELECTWRAP.clientHeight;
// el.scrollTop !== 0 当输入时,如果搜索结果很少,以至于没看到滚动条,那么此时的CONDITION计算结果是true,会执行bind.value(),此时不应该执行,否则搜索结果不匹配
if (CONDITION && SELECTWRAP.scrollTop !== 0) {
binding.value();
}
});
},
},
},
data() {
return {
pageNum: 1,
data: [],
keyword: "", // 存储关键字用
loading: false,
hasMore: true,
selectValue: null,
};
},
watch: {
value: {
immediate: true, // 立即执行
handler(newVal, oldVal) {
this.selectValue = null;
if (newVal) {
this.selectValue = newVal;
this.getList({ id: newVal });
}
},
},
},
methods: {
selectChange(value) {
let selectData = this.data.find((item) => item[this.dictValue] == value);
this.$emit("selectChange", selectData);
},
// 请求下一页的数据
loadMore() {
if (this.hasMore) {
this.pageNum++;
let req = {
pageNum: this.pageNum,
pageSize: this.pageSize,
};
req[this.selectArr] = this.keyword;
this.getList(req);
}
},
// 选中下拉框没有数据时,自动请求第一页的数据
focus() {
this.data = [];
this.keyword = "";
if (!this.data.length) {
this.pageNum = 1;
this.getList({ pageNum: this.pageNum, pageSize: this.pageSize });
}
},
// 发送请求搜索
handleSearch(keyword) {
this.data = [];
this.keyword = keyword;
let req = {
pageNum: 1,
pageSize: this.pageSize,
};
req[this.selectArr] = keyword;
this.getList(req);
},
getList(req) {
this.loading = true;
this.request(req).then((res) => {
let resData = res[this.responseValue];
this.data = [...this.data, ...resData];
this.hasMore = this.data.length < res.total;
this.loading = false;
});
},
// 删除选中时,如果请求了关键字,则清除关键字再请求第一页的数据
clear() {
this.data = [];
if (this.keyword) {
this.keyword = "";
this.pageNum = 1;
this.getList({ pageNum: this.pageNum, pageSize: this.pageSize });
}
},
},
};
</script>
效果图:
确保可以使用id查询,否则无法回显