vxe-table 将行与列反转展示

在日常开发中,我们常遇到这样的需求:将一张常规表格(行=记录,列=字段)转置展示,即把原表的列名变为行数据,原表的每一行数据变为新表的一列。这种“行列反转”在统计报表、数据对比、参数配置等场景中非常实用。
vxe-table 本身不提供内置的转置功能,但借助其灵活的 columns 和 data 配置,我们可以通过简单的数据转换轻松实现。本文将详细拆解实现逻辑,并提供可复用的代码模板。

需求场景与效果预览

假设原表格结构如下(横向展示多条记录的多个字段):

ID Name Role Sex Age Address
10001 Test1 Develop Man 28 Shenzhen
10002 Test2 Test Women 22 Beijing
... ... ... ... ... ...

转置后,我们希望得到这样的表格:

字段名 记录1 记录2 记录3 ...
ID 10001 10002 10003 ...
Name Test1 Test2 Test3 ...
Role Develop Test PM ...
Sex Man Women Man ...
Age 28 22 32 ...
Address Shenzhen Beijing Shanghai ...

即原字段作为行,原每条记录作为列,形成类似“数据透视”的展示方式。

核心实现思路

vxe-grid 的数据由 columns(列定义)和 data(数据行)决定。要实现转置,我们需要:

  • 新表头(columns):原数据的每一条记录对应新表的一列(col1, col2, ...),并增加一个固定列用于显示原字段名。
  • 新数据(data):原表的每个字段(field)对应新表的一行,该行的各列值即为原数据中各记录的对应字段值。

因此,转换逻辑本质上是二维数组的转置操作,只是我们保留原字段名作为第一列的值。

分步实现详解

准备原始数据

定义原始列配置 myColumns(包含所有字段)和原始数据 myData(多条记录):

const myColumns = [
  { field: 'id', title: 'ID' },
  { field: 'name', title: 'Name' },
  // ... 更多字段
]
const myData = [
  { id: 10001, name: 'Test1', ... },
  { id: 10002, name: 'Test2', ... },
  // ... 更多记录
]

编写转换函数 reverseTable

该函数负责构建新表格的 columns 和 data:

const reverseTable = () => {
  // 1. 构建新数据:每个原字段对应一行,行内各列为原各条记录的值
  const buildData = myColumns.map((column) => {
    const item = { col0: column.title }          // 第一列存放字段名(原title)
    myData.forEach((row, index) => {
      item[`col${index + 1}`] = row[column.field] // 动态列名 col1, col2, ...
    })
    return item
  })

  // 2. 构建新列定义:第一列固定显示字段名,其余列对应原各条记录
  const buildColumns = [
    { field: 'col0', fixed: 'left', width: 100 }  // 固定左侧便于浏览
  ]
  myData.forEach((_, index) => {
    buildColumns.push({
      field: `col${index + 1}`,
      minWidth: 200       // 可根据内容调整
    })
  })

  // 3. 赋值给 gridOptions
  gridOptions.data = buildData
  gridOptions.columns = buildColumns
}

关键点说明:

  • col0 固定列用于展示原字段名,使用 fixed: 'left' 使其在水平滚动时保持可见。
  • 动态列名 col1, col2, ... 对应原数据中的第1条、第2条记录,顺序与原数组索引一致。
  • minWidth: 200 保证内容较长的字段(如 Address)能完整展示,也可根据需要设为固定 width。

样式微调(可选)

为了让转置后的表格更易读,通常将第一列(字段名列)赋予特殊背景色,突出其“标签”属性

.reverse-table .vxe-body--row .vxe-body--column:first-child {
  background-color: #f8f8f9;
}

代码

image

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

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

const gridOptions = reactive({
  border: true,
  showOverflow: true,
  height: 400,
  showHeader: false,
  columns: [],
  data: []
})
const myColumns = [
  { field: 'id', title: 'ID' },
  { field: 'name', title: 'Name' },
  { field: 'role', title: 'Role' },
  { field: 'sex', title: 'Sex' },
  { field: 'age', title: 'Age' },
  { field: 'address', title: 'Address' },
  { field: 'rate', title: 'Rate' },
  { field: 'date3', title: 'Date' },
  { field: 'updateTime', title: 'UpdateTime' },
  { field: 'createTime', title: 'CreateTime' }
]
const myData = [
  { id: 10001, name: 'Test1', nickname: 'T1', role: 'Develop', sex: 'Man', age: 28, rate: 2, address: 'Shenzhen', date3: '20:30', updateTime: '2020-09-16', createTime: '2020-09-16' },
  { id: 10002, name: 'Test2', nickname: 'T2', role: 'Test', sex: 'Women', age: 22, rate: 2, address: 'Beijin', date3: '20:30', updateTime: '2019-09-16', createTime: '2020-09-16' },
  { id: 10003, name: 'Test3', nickname: 'T3', role: 'PM', sex: 'Man', age: 32, rate: 6, address: 'Shanghai', date3: '20:30', updateTime: '2020-09-16', createTime: '2021-09-16' },
  { id: 10004, name: 'Test4', nickname: 'T4', role: 'Designer', sex: 'Women', age: 23, rate: 2, address: 'Shenzhen', date3: '20:30', updateTime: '2020-09-16', createTime: '2020-09-16' },
  { id: 10005, name: 'Test5', nickname: 'T5', role: 'Develop', sex: 'Women', age: 30, rate: 10, address: 'Shanghai Beijin Shenzhen Shenzhen Guangzhou', date3: '20:30', updateTime: '2020-01-16', createTime: '2020-10-16' },
  { id: 10006, name: 'Test6', nickname: 'T6', role: 'Designer', sex: 'Women', age: 21, rate: 2, address: 'Shenzhen', date3: '20:30', updateTime: '2018-09-16', createTime: '2020-09-16' },
  { id: 10007, name: 'Test7', nickname: 'T7', role: 'Test', sex: 'Man', age: 29, rate: 3, address: 'Shenzhen', date3: '20:30', updateTime: '2020-01-16', createTime: '2020-10-16' },
  { id: 10008, name: 'Test8', nickname: 'T8', role: 'Develop', sex: 'Man', age: 35, rate: 2, address: 'Beijin Beijin Beijin', date3: '20:30', updateTime: '2017-09-16', createTime: '2020-09-16' },
  { id: 10009, name: 'Test9', nickname: 'T9', role: 'Test', sex: 'Man', age: 29, rate: 3, address: 'Shenzhen', date3: '20:30', updateTime: '2020-01-16', createTime: '2020-10-16' },
  { id: 10010, name: 'Test10', nickname: 'T10', role: 'Develop', sex: 'Man', age: 50, rate: 5, address: 'Shenzhen', date3: '20:30', updateTime: '2017-09-16', createTime: '2020-09-16' }
]

const reverseTable = () => {
  const buildData = myColumns.map((column) => {
    const item = { col0: column.title }
    myData.forEach((row, index) => {
      item[`col${index + 1}`] = row[column.field]
    })
    return item
  })
  const buildColumns = [{ field: 'col0', fixed: 'left', width: 100 }]
  myData.forEach((item, index) => {
    buildColumns.push({
      field: `col${index + 1}`,
      minWidth: 200
    })
  })
  gridOptions.data = buildData
  gridOptions.columns = buildColumns
}

reverseTable()
</script>

<style lang="scss">
.reverse-table .vxe-body--row .vxe-body--column:first-child {
  background-color: #f8f8f9;
}
</style>

注意事项与优化建议

  • 数据量限制

    • 转置后,列数 = 原记录数,行数 = 原字段数。若原记录过多(如超过 50 条),新表会有大量列,水平滚动体验变差。建议对记录数进行分页或限制展示条数。
  • 字段值为对象或复杂类型

    • 若原字段值为对象、数组等,直接赋值会显示 [object Object]。请在转换时进行格式化,例如调用 JSON.stringify 或提取特定属性。
  • 缺失值处理

    • 若原记录中某些字段不存在,row[column.field] 会返回 undefined,单元格将显示空。可根据需要设置默认值(如 '—')。
  • 表头与列名

    • 示例中设置 showHeader: false,因为第一行(字段名)已承担表头角色。若需显示列标题(如“记录1”、“记录2”),可保留 showHeader: true,并在 buildColumns 中设置 title 属性。
  • 固定列与滚动

    • 将第一列固定(fixed: 'left')有助于用户在横向滚动时始终看到字段名称,提升可读性。
  • 动态更新

    • 若原始数据变化,需重新调用 reverseTable 更新 gridOptions。可将其封装为方法,并在数据变更时触发。

通过简单的数据映射,我们利用 vxe-table 的基础能力实现了行列反转功能。代码清晰、无侵入,且保留了组件原有的排序、筛选、导出等扩展能力。
该方法适用于字段数量有限、记录数量适中的场景,是数据透视展示的一种轻量级替代方案。若需更复杂的多维分析,可考虑集成专业的透视表库,但对于大多数管理后台需求,本方案已足够。

https://vxetable.cn

posted @ 2026-08-24 13:45  独行者r2  阅读(1)  评论(0)    收藏  举报