vue+element select组件结合vue-virtual-scroll-list插件解决数据量太大,导致渲染过慢

2,458 阅读2分钟

本文已参与【新人创作礼】活动,一起开启掘金创作之路。

场景

因为项目中数据量有时候过于庞大,使用elementui的select组件时,会导致下拉框加载数据蛮并且卡顿甚至于卡死,为解决这个问题,发现vue-virtual-scroll-list这个插件,地址 www.npmjs.com/package/vue… ,用来模拟虚拟滚动,从而解决问题。

安装

    npm install vue-virtual-scroll-list --save

引入

    // 单个文件引入
    import virtualList from 'vue-virtual-scroll-list'
    
    // 注册组件
    components: { 'virtual-list': virtualList }

基础用法

一、要用这个插件去包裹需要循坏展示的标签。这里就是el-option标签

<el-select v-model="mediaAccount" popper-class="virtualSelect">
    <virtual-list style="max-height: 245px; overflow-y: auto;"
        :data-key="'id'"
        :data-sources="mediaAccountArr"
        :data-component="itemComponent"
        :keeps="20"
        :extra-props="{
            label: 'mediaAccountId',
            value: 'mediaAccountId'
        }" /> 
</el-select>


import ElOptionNode from './el-option-node';
// data
data(){
  return {
     mediaAccountArr: [
         // 示例数据 {id:1,mediaAccountId:1008666}
     ],
     itemComponent: ElOptionNode,
  }
}

抽离出el-option标签,新建el-option-node.vue文件

// el-option-node.vue
<template>
  <el-option :key="index" :label="source[label]" :value="source[value]"></el-option>
</template>

<script>
  export default {
    name: 'item-component',
    props: {
      index: { // 每一行的索引
        type: Number
      },
      source: { // 每一行的内容
        type: Object,
        default () {
          return {}
        }
      },
      label: { // 要显示的名称
        type: String
      },
      value: { // 绑定的值
        type: String
      },
    }
  }
</script>

参数:

1.png

  • data-key="'id'" 就是绑定的唯一key值
  • data-sources="mediaAccountArr" 下拉框的数组
  • data-component="itemComponent" 就是抽离中的el-option组件
  • keeps="20" 渲染的个数
  • extra-props 值为对象,可以传入自定义属性进去

注意点

<virtual-list style="max-height: 245px; overflow-y: auto;"
  1. 这里的样式一定要设置成最大高度,防止数据量少了时候下拉框显示多余空白地方
  2. 高度要设置成245px,不然会出现两个滚动条,会发生滚动bug
  3. 一定要设置y轴超出滚动
  4. select标签使用popper-class自定义一个类名,解决会出现两个滚动条的问题
<el-select popper-class="virtualSelect" />

<style>
.virtualSelect .el-scrollbar .el-scrollbar__bar.is-vertical{
    width: 0;
}
</style>

他默认渲染30个dom标签出来(我通过keeps配置成20个),到这里基本就解决了数据量大的卡顿问题。因为以往是有多少个下拉框就好渲染多少个dom标签。

3.png

实现模糊搜索功能

  1. 这就需要两个数组,一个是显示在页面上的数组,一个是全量数据的数组,在data中定义
data(){
  return {
     virtualoptions: [], // 在定义个存全量数据的数组
  }

2.使用select自带的filterable,remote属性实现搜索功能,remote-method方法实现过滤数据

<el-select @visible-change="visibleVirtualoptions" filterable remote :remote-method="remoteMethod" >
</el-select>

 methods: {
    remoteMethod(query) {
        if (query !== '') {
            this.mediaAccountArr = this.virtualoptions.filter(item => {
            return item.mediaAccountId.toLowerCase()
                .indexOf(query.toLowerCase()) > -1;
            });
        } else {
            this.mediaAccountArr = this.virtualoptions;
        }
    },
    visibleVirtualoptions(bool) {
        if(!bool) {
            this.$refs.virtualList.reset()
            setTimeout(() => {
                this.mediaAccountArr = this.virtualoptions;
            }, 200);
        }
    } 
 }
  • visible-change属性实现下拉框出现/隐藏时触发虚拟列表重置和把列表重置成全量数据

3.以上代码基本已实现功能,如下图 a1.gif

后续

考虑到项目中会有很多地方会用到这个功能,所以打算封装成组件。