Element-uiでは、セレクター(選択)の大量のオプションデータによって引き起こされるレンダリングの遅延とページのフリーズの問題が解決されています

ビジネスシナリオ:サーバーが20,000を超えるデータを返し、ドロップダウンボックスに表示する必要があります。直接レンダリングすると、ページがフリーズし、待機に時間がかかります。ユーザーエクスペリエンスが非常に悪いため、最適化します。このel-selectして、コードを直接アップロードします。

関連ナレッジポータル:
Vueはカスタムディレクティブとアプリケーションシナリオを実装します
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>

最後に、20,000を超えるデータのユーザーは、スクロールし続けて目的のデータを見つけることができません。検索機能を実現するにはフィルター可能な属性を設定することを忘れないでください
ここに画像の説明を挿入します
問題: element-uiのフィルター可能な属性のみが設定されている場合、検索範囲は遅延読み込みのみであり、データがスクロールアウトされているため、検索が不完全で不正確になります。
ここに画像の説明を挿入します

この問題を解決するために、引き続き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>

効果:
ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/ZYS10000/article/details/111822862