返回

Vue Virtual Scroller 与 Element UI Table 集成方案

vue.js

Vue-virtual-scroller 与 Element UI Table 的集成

Element UI Table 组件基于配置式渲染表格行,它不像一些组件允许开发者直接控制每一行的渲染,这使得与 vue-virtual-scroller 集成遇到一些挑战。vue-virtual-scroller 旨在高效渲染大型列表,通过只渲染视口内的元素来提高性能。 本文分析此问题,并给出一些可能的解决方案。

问题分析

核心在于, el-table 使用内部逻辑来渲染行,并未暴露可以直接使用 vue-virtual-scroller 迭代的行容器。传统上, vue-virtual-scroller 需要你迭代一个数组,并用它包裹每一个渲染出来的项目(列表项或者表格行)。 但在Element UI 的Table中, el-table-column 组件的是列配置,而非行的构成。这种机制意味着你无法直接使用 v-virtual-scroller 包裹 el-table 的每一行。

解决方案

方案一: 使用 el-table 的插槽和虚拟滚动组件

此方案的核心在于,利用 el-table 的插槽自定义渲染每一行, 并引入虚拟滚动组件。你可以使用一个带有height属性的div 来模拟 el-table 渲染的每一行,并且利用vue-virtual-scroller渲染该div,达到虚拟滚动效果。

  1. 创建虚拟滚动包装器 : 构建一个通用组件来包裹 el-table 的行渲染。 这个组件内部使用 vue-virtual-scroller 负责滚动。
<template>
  <virtual-scroller
      :items="tableData"
      :item-size="rowHeight"
      ref="scroller"
  >
      <template v-slot="{ item }">
      <div :style="{height: rowHeight + 'px', lineHeight: rowHeight + 'px'}" class="custom-table-row">
           <slot :item="item"></slot>
       </div>
      </template>
  </virtual-scroller>
</template>

<script>
    import { VirtualScroller } from 'vue-virtual-scroller'
    export default{
      name: "CustomTable",
      props:{
           tableData:{
               type: Array,
               required: true,
           },
           rowHeight:{
               type: Number,
               default: 40, // 设置行高度
           }
      },
        components:{
            VirtualScroller,
        },
    }
</script>

<style scoped>
    .custom-table-row {
        border-bottom: 1px solid #ebeef5;
    }
</style>
  1. 使用包装器替换表格 : 修改 el-table 组件,使用上述包装器替换数据迭代渲染逻辑,并将表格行的渲染放到该组件的slot中。
<template>
  <div>
    <el-table style="width: 100%;" :header-cell-style="{background:'#eef0f3',color:'#606266'}">
        <el-table-column
          v-for="(item, index) in columns"
          :key="index"
          :prop="item.prop"
          :label="item.label"
          :width="item.width">
        </el-table-column>
    </el-table>
    <CustomTable :table-data="tableData" :row-height="40">
       <template v-slot="{item}">
           <el-table style="width: 100%"  :border="false" :show-header="false">
             <el-table-column
               v-for="(col,index) in columns"
                :key="index"
              :prop="col.prop"
             >
                <template v-slot>
                    <span> {{ item[col.prop] }}</span>
               </template>
            </el-table-column>
            </el-table>
       </template>
    </CustomTable>

  </div>
</template>

<script>
  import CustomTable from './CustomTable.vue'; // 导入自定义包装器组件
export default {
    components: { CustomTable},
  data(){
      return {
          columns:[{
             prop:'date',
              label: 'Date',
                width: 180,
            },
            {
               prop:'name',
               label:'Name',
                 width:180,
            }],
            tableData:[
                { date: '2016-05-03', name: 'Tom' },
              { date: '2016-05-02', name: 'Bob' },
              { date: '2016-05-04', name: 'Marry' },
             { date: '2016-05-01', name: 'Jack' },
                  { date: '2016-05-05', name: 'Tom' },
                 { date: '2016-05-06', name: 'Tom' },
              { date: '2016-05-07', name: 'Tom' },
              { date: '2016-05-08', name: 'Tom' },
               { date: '2016-05-09', name: 'Tom' },
              { date: '2016-05-10', name: 'Tom' },
               { date: '2016-05-11', name: 'Tom' },
              { date: '2016-05-12', name: 'Tom' },
                { date: '2016-05-13', name: 'Tom' },
                  { date: '2016-05-14', name: 'Tom' },
              { date: '2016-05-15', name: 'Tom' }
            ]
      }
  },
}
</script>

这个方法核心是将行的渲染权交给自定义组件。它使用 vue-virtual-scroller 渲染一个占位的 div 模拟行的渲染。这带来了一些灵活性,但可能在样式控制上略显复杂。

方案二: 修改Element UI 的表格源码 (高阶)

另一种相对复杂的办法, 可以直接修改Element UI 的表格组件, 允许开发者使用 v-for 指令渲染行,这涉及到fork element UI项目修改其源代码,因此这个方案需要开发者对Element UI组件内部结构比较熟悉。

步骤简述 :

  1. Fork Element UI 代码仓库到本地。
  2. 定位 el-table 相关组件的源码。
  3. 修改表格渲染逻辑,使其可以接受外部传递的数据,然后配合vue-virtual-scroller组件。

这通常比较复杂且有侵入性,不推荐,因为这会让你的项目与你所使用的第三方库深度绑定。任何Element UI版本更新可能需要重新进行类似修改。

总结

vue-virtual-scroller 集成到 Element UI Table 中并非易事,因为两个组件的设计理念不同。方案一 通过创建中间组件作为桥梁,实现表格的虚拟滚动是一个较为可行的方案,尽管它增加了一层组件包装,在复杂度可以接受的范围内提高了表格性能,而 方案二 虽然是一种方式,但是不推荐。

无论你采用哪种方法, 都需要仔细考虑项目具体需求,评估方案可行性和潜在的维护成本。在着手修改之前,尽可能熟悉每一个组件,对可能造成影响的点做好测试。