select懒加载解决el-option数量过多导致页面加载慢

需求:在一个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)) || [];
};