解决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>

注:参考链接只是在百度搜索到的,有的未找到原文链接,如有问题私信我修改或删除
以上代码还可以优化,在搜索的结果也进行分页(有兴趣的可以搞一下)

posted @ 2021-03-30 10:28  聂显达  阅读(2594)  评论(0编辑  收藏  举报