Skip to content

Virtualized Table 虚拟化表格

在前端开发领域,表格一直都是一个高频出现的组件,尤其是在中后台和数据分析场景。但是,对于 Table V1 来说,当一屏里超过 1000 条数据记录时,就会出现卡顿等性能问题,体验不是很好。

通过虚拟化表格组件,超大数据渲染将不再是一个头疼的问题。

TIP

该组件仍在测试中,生产环境使用可能有风险。若您发现了 bug 或问题,请于 GitHub 报告给我们以便修复。同时,有一些 API 并未在此文档中提及,因为部分还没有开发完全,因此我们不在此提及。

即使虚拟化的表格是高效的,但是当数据负载过大时,网络内存容量也会成为您应用程序的瓶颈。因此请牢记,虚拟化表格永远不是最完美的解决方案,请考虑数据分页、过滤器等优化方案。

ts
import { createApp } from 'vue'
import { TableV2 as ElTableV2, AutoResizer as ElAutoResizer } from '@szhn/dh-design-pc'

const app = createApp()
app.use(ElTableV2)
app.use(ElAutoResizer)

基础用法

让我们演示虚拟化表的性能,用 10 列和 1000 行渲染一个基本示例。

<template>
  <el-auto-resizer style="height: 400px;">
    <template #default="{ width, height }">
      <el-table-v2
        :columns="columns"
        :data="data"
        :width="width"
        :height="height"
        fixed
      />
    </template>
  </el-auto-resizer>
</template>

<script lang="ts" setup>
import { TableV2 as ElTableV2, AutoResizer as ElAutoResizer } from '@szhn/dh-design-pc'


const generateColumns = (length = 10, prefix = 'column-', props?: Record<string, unknown>) =>
  Array.from({ length }).map((_, columnIndex) => ({
    ...props,
    key: `${prefix}${columnIndex}`,
    dataKey: `${prefix}${columnIndex}`,
    title: `Column ${columnIndex}`,
    width: 150,
  }))

const generateData = (
  columns: ReturnType<typeof generateColumns>,
  length = 200,
  prefix = 'row-',
) =>
  Array.from({ length }).map((_, rowIndex) => {
    return columns.reduce(
      (rowData, column, columnIndex) => {
        rowData[column.dataKey as string] = `Row ${rowIndex} - Col ${columnIndex}`
        return rowData
      },
      {
        id: `${prefix}${rowIndex}`,
        parentId: null,
      } as Record<string, unknown>,
    )
  })

const columns = generateColumns(10)
const data = generateData(columns, 1000)
</script>

固定列

通过列配置中的 fixed: 'left' | 'right' 让列在横向滚动时保持固定。

<template>
  <el-auto-resizer style="height: 320px;">
    <template #default="{ width, height }">
      <el-table-v2
        :columns="columns"
        :data="data"
        :width="width"
        :height="height"
        fixed
      />
    </template>
  </el-auto-resizer>
</template>

<script lang="ts" setup>
import { TableV2 as ElTableV2, AutoResizer as ElAutoResizer } from '@szhn/dh-design-pc'


const columns = [
  { key: 'id', dataKey: 'id', title: 'ID', width: 80, fixed: true },
  { key: 'name', dataKey: 'name', title: '姓名', width: 150, fixed: true },
  { key: 'email', dataKey: 'email', title: '邮箱', width: 260 },
  { key: 'city', dataKey: 'city', title: '城市', width: 140 },
  { key: 'country', dataKey: 'country', title: '国家', width: 140 },
  { key: 'job', dataKey: 'job', title: '职位', width: 200 },
  { key: 'company', dataKey: 'company', title: '公司', width: 200 },
]

const data = Array.from({ length: 200 }, (_, i) => ({
  id: i + 1,
  name: `用户 ${i + 1}`,
  email: `user${i + 1}@example.com`,
  city: '海口',
  country: '中国',
  job: '前端工程师',
  company: 'DHdesign Studio',
}))
</script>

排序

通过列配置中的 sortable 以及表格的 sort-state 受控实现排序交互。

<template>
  <el-auto-resizer style="height: 320px;">
    <template #default="{ width, height }">
      <el-table-v2
        v-model:sort-state="sortState"
        :columns="columns"
        :data="sortedData"
        :width="width"
        :height="height"
        @column-sort="onSort"
      />
    </template>
  </el-auto-resizer>
</template>

<script lang="ts" setup>
import { ref, computed } from 'vue'
import { TableV2 as ElTableV2, AutoResizer as ElAutoResizer } from '@szhn/dh-design-pc'


const columns = [
  { key: 'id', dataKey: 'id', title: 'ID', width: 100, sortable: true },
  { key: 'name', dataKey: 'name', title: '姓名', width: 180 },
  { key: 'score', dataKey: 'score', title: '分数', width: 140, sortable: true },
]

const rawData = Array.from({ length: 120 }, (_, i) => ({
  id: i + 1,
  name: `用户 ${i + 1}`,
  score: Math.floor(Math.random() * 100),
}))

const sortState = ref<{ key: string; order: 'asc' | 'desc' }>({ key: 'id', order: 'asc' })

const sortedData = computed(() => {
  const { key, order } = sortState.value
  return [...rawData].sort((a: any, b: any) =>
    order === 'asc' ? a[key] - b[key] : b[key] - a[key],
  )
})

const onSort = ({ key, order }: { key: string; order: 'asc' | 'desc' }) => {
  sortState.value = { key, order }
}
</script>

自定义单元格渲染器

当然,您可以根据您的需要呈现表格单元格。这是如何自定义您的单元格的简单例子。

<template>
  <el-auto-resizer style="height: 320px;">
    <template #default="{ width, height }">
      <el-table-v2
        :columns="columns"
        :data="data"
        :width="width"
        :height="height"
      />
    </template>
  </el-auto-resizer>
</template>

<script lang="ts" setup>
import { h } from 'vue'
import { TableV2 as ElTableV2, AutoResizer as ElAutoResizer, Tag as ElTag } from '@szhn/dh-design-pc'


const columns = [
  { key: 'id', dataKey: 'id', title: 'ID', width: 80 },
  { key: 'name', dataKey: 'name', title: '姓名', width: 180 },
  {
    key: 'status',
    dataKey: 'status',
    title: '状态',
    width: 160,
    cellRenderer: ({ cellData }: { cellData: string }) =>
      h(
        ElTag,
        { type: cellData === '在线' ? 'success' : 'info', effect: 'plain' },
        () => cellData,
      ),
  },
]

const data = Array.from({ length: 80 }, (_, i) => ({
  id: i + 1,
  name: `成员 ${i + 1}`,
  status: i % 2 === 0 ? '在线' : '离线',
}))
</script>

API

TableV2 Attributes

属性名说明类型默认值
columns列配置array
data表格数据array
width表格宽度number
height表格高度number
fixed是否有固定列booleanfalse
row-height行高number50
header-height表头高度number / number[]50
estimated-row-height动态行高下的估算值number
sort-state受控排序状态object

TableV2 Events

事件名说明
column-sort点击列头排序时触发
row-click行点击时触发
scroll滚动时触发

Column 配置(常用)

字段说明
key / dataKey列 key 与对应数据字段
title表头标题
width列宽
fixed是否固定
sortable是否可排序
cellRenderer自定义单元格渲染函数
headerCellRenderer自定义表头渲染函数

更多细节参见 Element Plus Virtualized Table 文档。