解决 Element-ui中 选择器(Select)因options 数据量大导致渲染慢、页面卡顿的问题

业务场景:服务端返回近两万多条数据需要在下拉框中展示,直接渲染会导致页面卡顿且需要很长时间等待,用户体验极差,所以我们把这个el-select优化一下,直接上代码。

相关知识传送门:

Vue实现自定义指令(directive)及应用场景

Vue中 实现函数的防抖、节流及应用场景

<template>
  <div class="content">
    <el-select v-model="chooseValue" filterable v-el-select-loadmore="loadMore(rangeNumber)">
      <el-option
        v-for="(item, index) in options.slice(0, rangeNumber)"
        :key="index"
        :label="item.label"
        :value="item.value">
      </el-option>
    </el-select>
  </div>
</template>
 
<script>
export default {
  data() {
    return {
      chooseValue: "",
      options: [],
      rangeNumber: 10,
    };
  },
  methods: { 
    getList() {
      // 测试数据25000条数据, 这里数据多少条无所谓,options.slice(0, rangeNumber)方法只会默认加载初始的10条数据
      for (let i = 0; i < 25000; i++) {
        this.options.push({label: "选择"+i,value:"选择"+i});
      } 
    },
    loadMore(n) {
      // n是默认初始展示的条数会在渲染的时候就可以获取,具体可以打log查看
      // elementui下拉超过7条才会出滚动条,如果初始不出滚动条无法触发loadMore方法
      return () => (this.rangeNumber += 5); // 每次滚动到底部可以新增条数  可自定义
    },
  },
  beforeMount() {
    this.getList();
  },
  directives:{
    'el-select-loadmore':(el, binding) => {
      // 获取element-ui定义好的scroll盒子
      const SELECTWRAP_DOM = el.querySelector(".el-select-dropdown .el-select-dropdown__wrap");
      if(SELECTWRAP_DOM){
        SELECTWRAP_DOM.addEventListener("scroll", function () {
          /**
           * scrollHeight 获取元素内容高度(只读)
           * scrollTop 获取或者设置元素的偏移值,
           *  常用于:计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.
           * clientHeight 读取元素的可见高度(只读)
           * 如果元素滚动到底, 下面等式返回true, 没有则返回false:
           * ele.scrollHeight - ele.scrollTop === ele.clientHeight;
           */
          const condition = this.scrollHeight - this.scrollTop <= this.clientHeight;
          if (condition) binding.value();
        });
      }
    },
  }
};
</script>

最后, 两万多条数据用户不可能一直滚动下去找自己想要数据,记得设置 filterable 属性,实现搜索功能;
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/e92e8023d6c44734befe9f87afba8e6b.png

问题: 如果仅设置 element-ui 的 filterable 属性 ,那么搜索的范围只有懒加载已滚动出的数据,导致搜索不全、不准确。

!在这里插入图片描述

为了解决这个问题,我们又继续使用了 filter-method 属性并结合 visible-change 事件,以及搜索输入时增加防抖进行优化。

最终代码

// utils.js
function _debounce(fn, delay = 300) {
  var timer = null;
  return function () {
    var _this = this;
    var args = arguments;
    if (timer) clearTimeout(timer); 
    timer = setTimeout(function () {
      fn.apply(_this, args);
    }, delay);
  };
}
export {
  _debounce
}

<template>
  <div class="content">
    <el-select 
      v-model="chooseValue" clearable filterable :filter-method="filterMethod" 
      v-el-select-loadmore="loadMore(rangeNumber)"
      @visible-change="visibleChange">
      <el-option
        v-for="(item, index) in options.slice(0, rangeNumber)"
        :key="index"
        :label="item.label"
        :value="item.value">
      </el-option>
    </el-select>
  </div>
</template>
 
<script>
import {_debounce} from '@/utils/index.js'
export default {
  data() {
    return {
      chooseValue: "",
      options: [],
      rangeNumber: 10,
      resOptions:[],
    };
  },
  methods: { 
    // 模拟获取大量数据
    getList() {
      // 测试数据15000条数据, 这里数据多少条无所谓,options.slice(0, rangeNumber)方法只会默认加载初始的10条数据
      for (let i = 0; i < 25000; i++) {
        this.resOptions.push({label: "选择"+i,value:"选择"+i});
      } 
    },
    loadMore(n) {
      // n是默认初始展示的条数会在渲染的时候就可以获取,具体可以打log查看
      // elementui下拉超过7条才会出滚动条,如果初始不出滚动条无法触发loadMore方法
      return () => (this.rangeNumber += 5); // 每次滚动到底部可以新增条数  可自定义
    },
    // 筛选方法
    filterMethod:_debounce(function(filterVal){
      if(filterVal){
        let filterArr = this.resOptions.filter((item)=>{
          return item.label.toLowerCase().includes(filterVal.toLowerCase())
        })
        this.options = filterArr;
      }else{
        this.options = this.resOptions;
      }
    },500),
    // 下拉框出现时,调用过滤方法
    visibleChange(flag){
      if(flag){
        this.filterMethod()
      }
    },
  },
  beforeMount() {
    this.getList();
  },
  directives:{
    'el-select-loadmore':(el, binding) => {
      // 获取element-ui定义好的scroll盒子
      const SELECTWRAP_DOM = el.querySelector(".el-select-dropdown .el-select-dropdown__wrap");
      if(SELECTWRAP_DOM){
        SELECTWRAP_DOM.addEventListener("scroll", function () {
          /**
           * scrollHeight 获取元素内容高度(只读)
           * scrollTop 获取或者设置元素的偏移值,
           *  常用于:计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.
           * clientHeight 读取元素的可见高度(只读)
           * 如果元素滚动到底, 下面等式返回true, 没有则返回false:
           * ele.scrollHeight - ele.scrollTop === ele.clientHeight;
           */
          const condition = this.scrollHeight - this.scrollTop <= this.clientHeight;
          if (condition) binding.value();
        });
      }
    },
  }
};
</script>

效果
在这里插入图片描述

转载https://juejin.cn/post/7025120300563955720

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
element-ui的日期选择器组件el-date-picker可以通过picker-options属性来控制日期选择的范围。\[1\]在使用el-date-picker组件时,可以通过设置picker-options属性来限制日期的选择范围。例如,可以设置最小日期和最大日期来限制选择的范围。具体的使用方法可以参考官方文档的示例代码。\[1\]在代码,可以通过设置picker-options属性来指定日期的选择范围。例如,可以设置minDate和maxDate来限制选择的范围。\[2\]另外,还可以使用start-placeholder和end-placeholder属性来设置日期选择器的起始日期和结束日期的占位符文本。\[3\] #### 引用[.reference_title] - *1* *3* [Element-UI:el-date-picker里的picker-options——用来限制选择日期的范围](https://blog.csdn.net/xwh19961210/article/details/114400397)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Element-UI日期选择器el-date-picker给指定日期添加红点标注](https://blog.csdn.net/weixin_43220182/article/details/128821693)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值