解決element-ui下拉框數據過多,導致頁面卡頓問題與本地分頁功能實現


效果

前情提要:

最近使用element-ui開發的一個頁面,在打開的時候占用cpu非常高,有時候都能達到90%↑。在調試時發現其中一個下拉框的接口返回2k↑的數據。本着有問題問百度的精神,看到主要的解決方案有如下兩種:

  1. 監聽下拉框滾動事件,去服務端請求數據 https://blog.csdn.net/zhangshineng/article/details/89676413?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

  2. 渲染一部分數據,其余部分需要手動篩選 https://www.cnblogs.com/mianbaodaxia/p/11153341.html

方案1:分頁獲取數據,根據select觸發事件去接口獲取下一頁。方案2:渲染一部分數據,其余數據需手動輸入篩選。兩種方案的核心都是將數據獲取與渲染dom分開(渲染時性能消耗較大),我的數據最多有2K條左右,讓后端加一個接口感覺不太合適,參考以上兩種方案,本地進行優化
1.前端獲所有數據實現本地分頁
2.可輸入文字篩選待選項

代碼 https://github.com/dadademo/demo/blob/main/src/components/select.vue

<template>
  <div>
    <el-select class="order-cover-select" v-model="selectModel" clearable placeholder="請選擇設備名稱" filterable multiple collapse-tags v-el-select-loadmore="loadmore" :filter-method="filterVmModel">
      <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id">
      </el-option>
    </el-select>
  </div>
</template>

<script>
// select 分頁
export default {
  name: 'selectDemo',
  // 此處詳見:https://blog.csdn.net/zhangshineng/article/details/89676413?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
  // 文檔:https://cn.vuejs.org/v2/guide/custom-directive.html
  directives: {
    // 計算是否滾動到最下面
    'el-select-loadmore': {
      bind (el, binding) {
        // 獲取element-ui定義好的scroll盒子 
        const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap');
        SELECTWRAP_DOM.addEventListener('scroll', function () {
          /**
          * scrollHeight 獲取元素內容高度(只讀)
          * scrollTop 獲取或者設置元素的偏移值,常用於, 計算滾動條的位置, 當一個元素的容器沒有產生垂直方向的滾動條, 那它的scrollTop的值默認為0.
          * clientHeight 讀取元素的可見高度(只讀)
          * 如果元素滾動到底, 下面等式返回true, 沒有則返回false:
          */
          const condition = Math.round(this.scrollHeight - this.scrollTop) <= this.clientHeight;
          if (condition) {
            binding.value();
          }
        });
      }
    }
  },
  data () {
    return {
      selectModel: '',// select 選擇的數據
      optionAll: [], // 全部的數據
      options: [], // 分頁數據
      // 分頁參數
      query: {
        page: 1,
        limit: 10
      },
      filterText: '' // 篩選文本
    }
  },
  created () {
    this.initData()
  },
  methods: {
    // 初始化數據
    initData () {
      // http request....
      // 模擬2k條數據
      let demoData = []
      for (let index = 0; index < 2000; index++) {
        demoData.push({ name: `測試${index}`, id: index })
      }
      this.optionAll = demoData
      this.loadmore(true)
    },
    // 分頁方法 詳見 directives
    loadmore (firstTag) {
      // 篩選時下拉不觸發分頁 
      if (!this.filterText) {
        if (!firstTag) {
          this.query.page++
        }
        // 前端分頁簡單版本
        // 分頁開始坐標
        const begin = this.query.limit * (this.query.page - 1)
        // 分頁結束坐標
        const end = (this.query.limit * (this.query.page - 1)) + this.query.limit
        // 這里使用slice 進行分頁
        this.options.push(...this.optionAll.slice(begin, end))
      }
    },
    // 篩選方法 
    // 此處詳見:https://www.cnblogs.com/mianbaodaxia/p/11153341.html 
    filterVmModel (value) {
      this.filterText = value
      // 篩選數據
      if (value) {
        this.options = this.optionAll.filter(item => {
          if (item.name && item.name.indexOf(value) !== -1) {
            return true
          } else {
            return false
          }
        })
      } else {
        // 直接賦值會連續觸發 loadmore 分頁事件
        this.options = []
        this.$nextTick(() => {
          this.options = this.optionAll.slice(0, this.query.limit * this.query.page)
        })
      }
    },
  }
}
</script>

注:參考鏈接只是在百度搜索到的,有的未找到原文鏈接,如有問題私信我修改或刪除
以上代碼還可以優化,在搜索的結果也進行分頁(有興趣的可以搞一下)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM