vxe-table 高性能渲染单元格图表:柱状图与饼图

在数据密集型表格中,将统计图表直接嵌入单元格,可以极大提升数据可读性与决策效率。vxe-table 原生支持柱状图(条形图)与饼图(含环形图、多饼混合)的单元格渲染,具备以下核心能力:

  • 高性能:基于 Canvas 轻量绘制,配合虚拟滚动,支持万级数据流畅滚动。
  • 高灵活性:支持自定义颜色、标签、提示框(tooltip)、数值范围、环形内径等。
  • 多数据格式:数组形式传入数值(如 [30, 70]),自动计算占比或绘制多系列柱状图。
  • 混合渲染:一个单元格内可渲染多个独立饼图(pies 渲染器)。

柱状图

柱状图渲染器名称为 bar,通过 cellRender 配置即可在表格列中展示横向或纵向进度条(默认为横向百分比条)。支持单值、多值并列显示,并可以设置最大值、颜色、标签等。

参数说明:

属性 类型 说明
bar.max number 柱状图的最大参考值,用于比例计算(默认自动取最大值或 100)
colors string[] 多系列柱状图的颜色数组,如 ['#FFDB5C', '#91C7AE']
labels string[] 多系列对应的图例标签,用于 tooltip 中的 {label} 占位符
label object 数值标签配置:{ formatter: '{value}%' },支持 {value} 占位符
tooltip object 提示框格式化:{ formatter: '{label}:{value}%' }

image

<template>
  <div>
    <vxe-grid v-bind="gridOptions"></vxe-grid>
  </div>
</template>

<script setup>
import { reactive } from 'vue'

const num10CellRender = reactive({
  name: 'bar',
  props: {
    bar: {
      max: 100
    },
    label: {
      formatter: '{value}%'
    }
  }
})

const num11CellRender = reactive({
  name: 'bar',
  props: {
    label: {
      formatter: '{value}'
    }
  }
})

const num12CellRender = reactive({
  name: 'bar',
  props: {
    bar: {
      max: 140
    },
    colors: ['#FFDB5C', '#91C7AE', '#D48265'],
    labels: ['团队1', '团队2', '团队3'],
    tooltip: {
      formatter: '{label}:{value}%'
    },
    label: {
      formatter: '{value}%'
    }
  }
})

const gridOptions = reactive({
  border: true,
  showOverflow: true,
  height: 500,
  columnConfig: {
    resizable: true
  },
  columns: [
    { type: 'seq', width: 70 },
    { field: 'name', title: 'Name' },
    { field: 'num10', title: '柱状图', width: 200, cellRender: num10CellRender },
    { field: 'num11', title: '柱状图 - 显示值', width: 200, cellRender: num11CellRender },
    { field: 'num12', title: '柱状图 - 最大值', width: 200, cellRender: num12CellRender }
  ],
  data: [
    { id: 101, name: 'test1', num10: [60], num11: [60, 111], num12: [60, 134, 76] },
    { id: 102, name: 'test2', num10: [85], num11: [33, 25], num12: [42, 73, 22] },
    { id: 103, name: 'test3', num10: [45], num11: [60, 104], num12: [6, 64, 44] },
    { id: 104, name: 'test4', num10: [88], num11: [76, 99], num12: [41, 81, 77] },
    { id: 105, name: 'test5', num10: [72], num11: [27, 157], num12: [48, 101, 76] },
    { id: 106, name: 'test6', num10: [50], num11: [8, 111], num12: [60, 5, 19] },
    { id: 107, name: 'test7', num10: [16], num11: [60, 6], num12: [9, 57, 34] },
    { id: 108, name: 'test8', num10: [24], num11: [23, 68], num12: [35, 111, 80] },
    { id: 109, name: 'test9', num10: [100], num11: [14, 66], num12: [27, 34, 98] },
    { id: 1010, name: 'test10', num10: [98], num11: [44, 98], num12: [29, 107, 127] }
  ]
})
</script>

饼图

饼图渲染器名称为 pie(单个饼图)或 pies(多个小饼图混合)。支持环形图、实心饼图、自定义中央文字、提示框等。

参数说明

属性 类型 说明
ring object 环形配置:{ diameter: '60%', color: '#2F4554' }。diameter 为内径占比(百分比字符串),color 为中心颜色。不配置则为实心饼图。
colors string[] 扇区颜色数组
labels string[] 扇区标签,用于 tooltip 中的 {label} 占位符
label object 图表中央文本(仅环形图生效):{ color: '#fff', formatter: '概况' }。若需在每个扇区显示数值,可使用 formatter: '{value[0]}%'(显示第一个扇区的百分比)
tooltip object 提示框格式化:{ formatter: '{label}:{value}%' }

image

  • 多饼图混合渲染(pies)
    • 通过 children 数组配置多个独立饼图,每个子项支持上述 pie 的所有 props。
    • 数据格式:字段值必须为二维数组,外层数组长度与 children 数量一致,内层数组为每个小饼图的数据。
<template>
  <div>
    <vxe-grid v-bind="gridOptions"></vxe-grid>
  </div>
</template>

<script setup>
import { reactive } from 'vue'

const num20CellRender = reactive({
  name: 'pie',
  props: {
    ring: {
      diameter: '60%'
    }
  }
})

const num21CellRender = reactive({
  name: 'pie',
  props: {
    colors: ['#FFDB5C', '#F0F0F0'],
    ring: {
      diameter: '60%'
    },
    label: {
      formatter: '{value[0]}%'
    }
  }
})

const num23CellRender = reactive({
  name: 'pie'
})

const num30CellRender = reactive({
  name: 'pie',
  props: {
    colors: ['#FFDB5C', '#91C7AE', '#D48265'],
    labels: ['团队1', '团队2', '团队3'],
    ring: {
      diameter: '60%',
      color: '#2F4554'
    },
    tooltip: {
      formatter: '{label}:{value}%'
    },
    label: {
      color: '#ffffff',
      formatter: '概况'
    }
  }
})

const num31CellRender = reactive({
  name: 'pies',
  children: [
    {
      props: {
        tooltip: {
          formatter: '值:{value}'
        },
        colors: ['#FFDB5C', '#D48265'],
        ring: { diameter: '60%' }
      }
    },
    {
      props: {
        tooltip: {
          formatter: '值:{value}'
        }
      }
    },
    {
      props: {
        tooltip: {
          formatter: '值:{value}'
        }
      }
    }
  ]
})

const gridOptions = reactive({
  border: true,
  showOverflow: true,
  height: 500,
  columnConfig: {
    resizable: true
  },
  columns: [
    { type: 'seq', width: 70 },
    { field: 'name', title: 'Name' },
    { field: 'num20', title: '饼图 - 环形', width: 100, cellRender: num20CellRender },
    { field: 'num21', title: '饼图 - 自定义环形', width: 140, cellRender: num21CellRender },
    { field: 'num23', title: '饼图 - 实心', width: 100, cellRender: num23CellRender },
    { field: 'num30', title: '饼图 - 自定义实心', width: 140, cellRender: num30CellRender },
    { field: 'num31', title: '多种混合', width: 200, cellRender: num31CellRender }
  ],
  data: [
    { id: 101, name: 'test1', num20: [30, 70], num21: [30, 70], num30: [47, 67, 67], num31: [[60, 28, 26], [77, 100], [77, 100, 8, 55, 100, 77, 142]], num23: [20, 30, 50] },
    { id: 102, name: 'test2', num20: [50, 50], num21: [60, 40], num30: [60, 83, 33], num31: [[28, 60, 32], [88, 40], [22, 100, 9, 55, 111, 86, 100]], num23: [200, 400, 500] },
    { id: 103, name: 'test3', num20: [33, 67], num21: [27, 78], num30: [84, 11, 14], num31: [[100, 17, 39], [100, 220], [7, 100, 11, 77, 105, 77, 100]], num23: [10, 80, 10] },
    { id: 104, name: 'test4', num20: [11, 89], num21: [50, 50], num30: [25, 71, 67], num31: [[19, 76, 99], [77, 702], [33, 100, 77, 66, 174, 69, 100]], num23: [80, 10, 10] },
    { id: 105, name: 'test5', num20: [19, 81], num21: [67, 33], num30: [100, 29, 55], num31: [[35, 63, 100], [53, 8], [77, 100, 66, 33, 100, 97, 100]], num23: [18, 30, 26] },
    { id: 106, name: 'test6', num20: [16, 84], num21: [17, 83], num30: [66, 100, 67], num31: [[13, 57, 60], [330, 546], [11, 100, 58, 72, 100, 178, 100]], num23: [14, 33, 26] },
    { id: 107, name: 'test7', num20: [98, 2], num21: [86, 14], num30: [60, 9, 5], num31: [[60, 40, 0], [120, 100], [22, 100, 77, 44, 10, 77, 198]], num23: [20, 5, 15] },
    { id: 108, name: 'test8', num20: [63, 37], num21: [99, 1], num30: [55, 76, 67], num31: [[46, 71, 83], [77, 100], [77, 100, 65, 97, 9, 59, 100]], num23: [10, 20, 30, 40] },
    { id: 109, name: 'test9', num20: [48, 52], num21: [8, 92], num30: [97, 60, 41], num31: [[55, 33, 53], [747, 52], [73, 100, 78, 81, 100, 77, 174]], num23: [14, 20, 36] },
    { id: 1010, name: 'test10', num20: [72, 28], num21: [22, 78], num30: [17, 10, 31], num31: [[77, 100, 58], [75, 85], [14, 250, 59, 44, 16, 50, 100]], num23: [200, 400, 500] }
  ]
})
</script>

大数据量

对于几万行数据选,丝滑流畅,启用虚拟滚动方式:virtual-scroll="{ gt: 0 }"

https://vxetable.cn

posted @ 2026-05-28 15:07  独行者r2  阅读(24)  评论(0)    收藏  举报