需求:在一个dialog中使用了多个el-select提供选择用户、角色、部门等入口,但是每次打开弹框的时候都需要等很久才能将已选数据回显出来,而且在页面加载完成前鼠标无法操作dailog
解决方案:
- 请求接口先获取到所有的option数组
- 首次只截取10条option数据,避免option过多导致页面卡顿
- 监听下拉框滚动事件,用户打开下拉框并滚动到下拉框底部后截取1-20条数据,以此类推
- 考虑到需要回显的老数据,在截取数据后从所有option数组中找到已选的用户并unshift进去(如果截取的option中有已选数据就不用)
实现步骤:
先自定义一个监听select下拉框滚动的指令,通过
export default {
mounted(el, { arg, value }) {
const SELECTWRAP_DOM = document.querySelector(
`.${arg} .el-select-dropdown__wrap`
);
SELECTWRAP_DOM &&
SELECTWRAP_DOM.addEventListener("scroll", function () {
const condition =
SELECTWRAP_DOM.scrollHeight - SELECTWRAP_DOM.scrollTop ==
SELECTWRAP_DOM.clientHeight;
if (condition && SELECTWRAP_DOM.scrollTop > 0) {
value();
}
});
},
};
main.js中全局注册这个自定义指令
import selLazyLoad from '@/directive/common/selLazyLoad'
app.directive('selLazyLoad', selLazyLoad)
html结构:
<el-select
v-model="libyModel.user"
multiple
filterable
v-selLazyLoad:[arg]="loadMore"
:popper-class="arg"
:filter-method="userFilterMethod"
:reserve-keyword="false"
placeholder="请选择"
style="width: 100%"
@change="changeLibyOpts('user')"
>
<el-option
v-for="item in userOptList"
:key="item.userId"
:label="item.nickName"
:value="item.userId"
:disabled="item.disabled"
>
{{ item.nickName }}
</el-option>
</el-select>
定义方法:
const loadMore = () => {
// 如果截取的长度==获取到的所有option长度将不再截取
if (userOptList.value.length == userOptions.value?.length) return;
userPageNum.value++;
getScrollUser();
};
// 截取页面显示的实际option
const getScrollUser = () => {
// 过滤出前十条用户信息+需要回显的数据
userOptList.value = userOptions.value.slice(0, userPageNum.value * 10);
if (libyModel.value.user?.length && userOptList.value?.length)
libyModel.value.user.forEach((item) => {
let hasOpt = userOptList.value.findIndex((val) => val.userId === item);
if (hasOpt > -1) return;
let findItem = userOptions.value.find((val) => val.userId === item);
findItem &&
userOptList.value.unshift({
...findItem,
});
});
};
// 搜索功能
const userFilterMethod = (value) => {
// 手动触发下拉框回滚至顶部,避免触发v-slLazyLoad指令
document.querySelector(
`.${props.arg} .el-select-dropdown__wrap`
).scrollTop = 0;
if (!value?.length) return getScrollUser();
userOptList.value =
userOptions.value.filter((item) => item.nickName?.includes(value)) || [];
};