Vxe UI vue vxe-table grid 性能优化,提高渲染性能

时间:2024-10-19 16:33:24

Vxe UI vue vxe-table vxe-grid 本身就支持虚拟滚动以及灵活的扩展,可也是由于太过灵活,可定制化程度太高,比如单元格自定义渲染,一旦写得不好,就会影响渲染卡顿。

vxe-table 和 vxe-grid

直接使用 vxe-grid,grid 的渲染性能是最优的,全部功能比 table 强非常多。

全局参数

对于不同项目,只需要利用好全局参数,基本上就可以实现无需封装了,基本上所有组件都支持全局参数配置。

整理了最优的全局参数配置:

import { VxeUI } from 'vxe-table'

VxeUI.setConfig({
  version: 0, // 版本号,比如使用了相关的浏览器本地储存功能,当组件升级后系统自动重置数据,那么只需要不断增加版本即可
  zIndex: 2000, // 弹出层的层级,一般设置 2000 就够了
  table: {
    border: true, // 表格边框
    showOverflow: true, // 单元格溢出隐藏,大幅提高渲染性能
    autoResize: true, // 自动根据父容器适应调整宽高
    columnConfig: {
      resizable: true // 列宽拖动调整宽度
    },
    editConfig: {
      trigger: 'click' // 默认点击编辑
    },
    sortConfig: {
      trigger: 'cell' // 默认单元格编辑
    },
    scrollX: {
      enabled: false, // 默认关闭横向虚拟滚动,一般横向使用很少,局部开启就可以
      gt: 15
    },
    scrollY: {
      enabled: true, // 默认启用纵向虚拟滚动
      gt: 20
    }
  },
  // grid 会默认继承 table,所以无需重复设置一样的参数
  grid: {
    toolbarConfig: {
      custom: true // 全局开启自定义列
    },
    // 数据代理相关配置,无使用就忽略
    proxyConfig: {
      showResponseMsg: false,
      showActiveMsg: true,
      response: {
        total: 'page.total',
        result: 'data',
        list: 'data'
      }
    }
  }
})

使用

高度是非常重要的参数,可以固定,也可以设置 100% 自适应父容器,提高渲染性能

一千行渲染
在这里插入图片描述
一万行渲染
在这里插入图片描述
十万行渲染
在这里插入图片描述

<template>
  <div>
    <p>
      <vxe-button @click="loadList(1000)">1k行</vxe-button>
      <vxe-button @click="loadList(5000)">5k行</vxe-button>
      <vxe-button @click="loadList(10000)">1w行</vxe-button>
      <vxe-button @click="loadList(50000)">5w行</vxe-button>
      <vxe-button @click="loadList(100000)">10w行</vxe-button>
    </p>
    <vxe-grid ref="gridRef" v-bind="gridOptions"></vxe-grid>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { VxeUI } from 'vxe-table'
const gridRef = ref()
const gridOptions = reactive({
  border: true,
  showOverflow: true,
  height: 800,
  loading: false,
  scrollY: {
    enabled: true,
    gt: 0
  },
  columns: [
    { type: 'seq', title: '序号', width: 100 },
    { field: 'name', title: 'Name', minWidth: 180 },
    { field: 'role', title: 'Role', width: 200 },
    { field: 'num', title: 'Num', width: 200 },
    { field: 'address', title: 'Address', width: 200 }
  ],
  data: []
})
// 模拟行数据
const loadList = (size = 200) => {
  gridOptions.loading = true
  setTimeout(() => {
    const dataList = []
    for (let i = 0; i < size; i++) {
      dataList.push({
        id: i,
        name: `名称${i} 名称名称 称`,
        role: `role ${i}`,
        num: 20,
        address: 'shenzhen shen'
      })
    }
    const $grid = gridRef.value
    if ($grid) {
      const startTime = Date.now()
      $grid.loadData(dataList).then(() => {
        VxeUI.modal.message({
          content: `加载时间 ${Date.now() - startTime} 毫秒`,
          status: 'success'
        })
        gridOptions.loading = false
      })
    }
  }, 350)
}
loadList(500)

</script>

可编辑

当列比较多时,就可以开启横向虚拟滚动,以下同时使用可编辑+纵向和横向虚拟滚动,极致流畅的渲染表格,同时还能支持任意扩展,单元格任意自定义(需要注意自定义的逻辑是否复杂,过度复杂会影响渲染性能)。

10000行 x 150列
在这里插入图片描述
滚动以及编辑输入都是丝滑流畅的
在这里插入图片描述

<template>
  <div>
    <p>
      <vxe-button @click="loadDataAndColumns(100, 50)">100行50列</vxe-button>
      <vxe-button @click="loadDataAndColumns(1000, 80)">1k行80列</vxe-button>
      <vxe-button @click="loadDataAndColumns(5000, 100)">5k行100列</vxe-button>
      <vxe-button @click="loadDataAndColumns(10000, 150)">1w行150列</vxe-button>
      <vxe-button @click="loadDataAndColumns(30000, 200)">3w行200列</vxe-button>
    </p>
    <p>
      <vxe-button @click="loadDataAndColumns(50, 50)">50行100列</vxe-button>
      <vxe-button @click="loadDataAndColumns(80, 1000)">80行1k列</vxe-button>
      <vxe-button @click="loadDataAndColumns(100, 5000)">100行5k列</vxe-button>
      <vxe-button @click="loadDataAndColumns(150, 10000)">200行1w列</vxe-button>
      <vxe-button @click="loadDataAndColumns(200, 30000)">200行3w列</vxe-button>
    </p>
    <vxe-grid ref="gridRef" v-bind="gridOptions"></vxe-grid>
  </div>
</template>

<script setup>
import { ref, reactive, onMounted } from 'vue'
import { VxeUI } from 'vxe-table'
const gridRef = ref()
const gridOptions = reactive({
  border: true,
  loading: false,
  showOverflow: true,
  showHeaderOverflow: true,
  showFooterOverflow: true,
  height: 800,
  editConfig: {
    trigger: 'click',
    mode: 'cell'
  },
  scrollY: {
    enabled: true,
    gt: 0
  },
  scrollX: {
    enabled: true,
    gt: 0
  }
})
// 模拟行与列数据
const loadDataAndColumns = (rowSize, colSize) => {
  gridOptions.loading = true
  setTimeout(() => {
    const $grid = gridRef.value
    const colList = []
    for (let i = 0; i < colSize; i++) {
      colList.push({
        field: `col${i}`,
        title: `标题${i}`,
        width: 160,
        editRender: { name: 'VxeInput' }
      })
    }
    const dataList = []
    for (let i = 0; i < rowSize; i++) {
      const item = {
        id: 10000 + i
      }
      for (let j = 0; j < colList.length; j++) {
        item[`col${j}`] = `值_${i}_${j}`
      }
      dataList.push(item)
    }
    if ($grid) {
      const startTime = Date.now()
      $grid.loadColumn(colList).then(() => {
        return $grid.loadData(dataList)
      }).then(() => {
        VxeUI.modal.message({
          content: `加载时间 ${Date.now() - startTime} 毫秒`,
          status: 'success'
        })
        gridOptions.loading = false
      })
    }
  }, 50)
}
onMounted(() => {
  loadDataAndColumns(50, 50)
})

</script>

更复杂的渲染

使用左右冻结列+复杂的单元格渲染、头像、上传图片、全屏预览,开关组件等

以下测试渲染1000-50000行速度
在这里插入图片描述

<template>
  <div>
    <vxe-button @click="loadData(5000)">加载5k条</vxe-button>
    <vxe-button @click="loadData(10000)">加载1w条</vxe-button>
    <vxe-button @click="loadData(50000)">加载5w条</vxe-button>
    <vxe-grid v-bind="gridOptions"></vxe-grid>
  </div>
</template>

<script setup>
import { reactive, nextTick } from 'vue'
import { VxeUI } from 'vxe-table'
const flag1CellRender = reactive({
  name: 'VxeSwitch'
})
const imgUrlCellRender = reactive({
  name: 'VxeImage',
  props: {
    width: 36,
    height: 36
  }
})
const imgList1CellRender = reactive({
  name: 'VxeUpload',
  props: {
    mode: 'image',
    readonly: true,
    moreConfig: {
      maxCount: 2
    },
    imageStyle: {
      width: 40,
      height: 40
    }
  }
})
const gridOptions = reactive({
  border: true,
  showOverflow: true,
  showHeaderOverflow: true,
  showFooterOverflow: true,
  loading: false,
  height: 800,
  columnConfig: {
    resizable: true
  },
  scrollX: {
    enabled: true,
    gt: 0
  },
  scrollY: {
    enabled: true,
    gt: 0
  },
  columns: [
    { title: '列0', field: 'col0', width: 100, fixed: 'left' },
    { title: '列1', field: 'imgUrl', width: 80, fixed: 'left', cellRender: imgUrlCellRender },
    { title: '列2', field: 'col2', width: 90, fixed: 'left' },
    { title: '列3', field: 'col3', width: 200 },
    { title: '列4', field: 'col4', width: 140 },
    { title: '列5', field: 'col5', width: 300 },
    { title: '列6', field: 'col6', width: 160 },
    { title: '列7', field: 'col7', width: 120 },
    { title: '列8', field: 'col8', width: 400 },
    { title: '列9', field: 'col9', width: 160 },
    { title: '列10', field: 'col10', width: 160 },
    { title: '列11', field: 'col11', width: 180 },
    { title: '列12', field: 'col12', width: 160 },
    { title: '列13', field: 'col13', width: 80 },
    { title: '列14', field: 'col14', width: 120 },
    { title: '列15', field: 'col15', width: 360 },
    { title: '列16', field: 'col16', width: 150 },
    { title: '列17', field: 'col17', width: 380 },
    { title: '列18', field: 'col18', width: 100 },
    { title: '列19', field: 'col19', width: 290 },
    { title: '列20', field: 'col20', width: 80 },
    { title: '列21', field: 'col21', width: 100 },
    { title: '列22', field: 'col22', width: 120 },
    { title: '列23', field: 'col23', width: 270 },
    { title: '列24', field: 'col24', width: 330 },
    { title: '列25', field: 'col25', width: 460 },