vue 表格组件 vxe-grid 自定义插槽模板的用法详解

vxe-grid 的自定义插槽非常灵活,单元格可以渲染图片、按钮、格式化文本,甚至多个元素的组合。插槽支持两种写法:模板插槽(Vue template 中的 #xxx_default)与 JSX 插槽(在列配置中直接返回 JSX)。两者能力等价,选择取决于项目是否已启用 JSX。本文说明两种写法的用法、插槽命名规则,以及渲染性能的取舍。

vxe-grid 如何用插槽自定义单元格内容?

在列配置中通过 slots: { default: '插槽名' } 指定插槽,模板中定义对应名称的插槽即可接管该列渲染。插槽名建议遵循 {field}_default 命名规则,便于识别与维护。

  • 生效前提:
    • 列上必须配置 slots.default,否则单元格按默认方式渲染字段值。
    • 模板插槽需在 vxe-grid 内定义,插槽名与 slots.default 的值一致。
    • JSX 插槽需将 script setup 的 lang 设为 jsx,并在列配置中直接写 default 函数。
  • 预期结果:指定列不再显示原始字段值,而是渲染插槽中定义的内容;分组列头中的子列同样可以使用插槽。

插槽参数有哪些?

两种写法接收的参数相同,均为一个对象,常用字段如下:

参数 类型 说明
row Object 当前行数据
column Object 当前列配置
rowIndex Number 当前行索引(从 0 开始)
columnIndex Number 当前列索引
$grid Object 表格实例,可调用表格方法

模板插槽通过解构使用:#imgUrl_default="{ row }";JSX 插槽通过函数参数使用:default({ row }) { ... }。

方式一:模板插槽

适用场景:项目未启用 JSX,或团队更习惯 Vue 模板语法。

<template>
  <div>
    <vxe-grid v-bind="gridOptions">
      <template #imgUrl_default="{ row }">
        <vxe-image :src="row.imgUrl" width="36" height="30"></vxe-image>
      </template>

      <template #name_default="{ row }">
        <vxe-button mode="text" @click="openDetail(row)">点击{{ row.name }}</vxe-button>
      </template>

      <template #sex_default="{ row }">
        <span>{{ formatSex(row) }}</span>
      </template>

      <template #address_default="{ row }">
        <vxe-image src="https://vxeui.com/resource/img/546.gif" width="36" height="30"></vxe-image>
        <span>{{ row.address }}</span>
        <vxe-image src="https://n.sinaimg.cn/sinacn17/w120h120/20180314/89fc-fyscsmv5911424.gif" width="30" height="30"></vxe-image>
      </template>
    </vxe-grid>
  </div>
</template>

<script setup>
import { reactive } from 'vue'
import { VxeUI } from 'vxe-pc-ui'

const gridOptions = reactive({
  border: true,
  showOverflow: true,
  columns: [
    { type: 'seq', width: 70 },
    { field: 'imgUrl', title: 'imgUrl', slots: { default: 'imgUrl_default' } },
    { field: 'name', title: 'Name', slots: { default: 'name_default' } },
    {
      title: 'Group1',
      children: [
        { field: 'sex', title: 'Sex', slots: { default: 'sex_default' } },
        { field: 'num', title: 'Number' },
        { field: 'age', title: 'Age' }
      ]
    },
    { field: 'address', title: 'Address', width: 200, slots: { default: 'address_default' } }
  ],
  data: [
    { id: 10001, name: 'Test1', role: 'Develop', sex: '0', age: 28, num: 234, imgUrl: 'https://vxeui.com/resource/img/fj577.jpg', address: 'test abc' },
    { id: 10002, name: 'Test2', role: 'Test', sex: '1', age: 22, num: 34, imgUrl: 'https://vxeui.com/resource/img/fj581.jpeg', address: 'Guangzhou' },
    { id: 10003, name: 'Test3', role: 'PM', sex: '0', age: 32, num: 12, imgUrl: 'https://vxeui.com/resource/img/fj581.jpeg', address: 'Shanghai' }
  ]
})

const formatSex = (row) => {
  return row.sex === '1' ? '男' : '女'
}

const openDetail = (row) => {
  VxeUI.modal.message({
    status: 'success',
    content: `点击了${row.name}`
  })
}
</script>

image

方式二:JSX 插槽

适用场景:项目已配置 JSX 支持,或列配置需要动态生成、希望渲染逻辑与列定义写在一起。

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

<script setup lang="jsx">
import { reactive } from 'vue'
import { VxeUI } from 'vxe-pc-ui'

const gridOptions = reactive({
  border: true,
  showOverflow: true,
  columns: [
    { type: 'seq', width: 70 },
    {
      field: 'imgUrl',
      title: 'imgUrl',
      slots: {
        default({ row }) {
          return <vxe-image src={row.imgUrl} width="36" height="30" />
        }
      }
    },
    {
      field: 'name',
      title: 'Name',
      slots: {
        default({ row }) {
          return (
            <vxe-button mode="text" onClick={() => openDetail(row)}>
              点击{row.name}
            </vxe-button>
          )
        }
      }
    },
    {
      title: 'Group1',
      children: [
        {
          field: 'sex',
          title: 'Sex',
          slots: {
            default: ({ row }) => {
              return <span>{formatSex(row)}</span>
            }
          }
        },
        { field: 'num', title: 'Number' },
        { field: 'age', title: 'Age' }
      ]
    },
    {
      field: 'address',
      title: 'Address',
      width: 200,
      slots: {
        default({ row }) {
          return (
            <div>
              <vxe-image src="https://vxeui.com/resource/img/546.gif" width="36" height="30" />
              <span>{row.address}</span>
              <vxe-image src="https://n.sinaimg.cn/sinacn17/w120h120/20180314/89fc-fyscsmv5911424.gif" width="36" height="30" />
            </div>
          )
        }
      }
    }
  ],
  data: [
    { id: 10001, name: 'Test1', role: 'Develop', sex: '0', age: 28, num: 234, imgUrl: 'https://vxeui.com/resource/img/fj577.jpg', address: 'test abc' },
    { id: 10002, name: 'Test2', role: 'Test', sex: '1', age: 22, num: 34, imgUrl: 'https://vxeui.com/resource/img/fj581.jpeg', address: 'Guangzhou' },
    { id: 10003, name: 'Test3', role: 'PM', sex: '0', age: 32, num: 12, imgUrl: 'https://vxeui.com/resource/img/fj581.jpeg', address: 'Shanghai' }
  ]
})

const formatSex = (row) => {
  return row.sex === '1' ? '男' : '女'
}

const openDetail = (row) => {
  VxeUI.modal.message({
    status: 'success',
    content: `点击了${row.name}`
  })
}
</script>

渲染效果与模板插槽完全一致。区别仅在于渲染逻辑写在列配置内,而非模板中。

模板插槽与 JSX 插槽如何选择?

维度 模板插槽 JSX 插槽
语法 Vue 模板 JSX
是否需要构建配置 否 需要 JSX 支持
渲染逻辑位置 模板中集中定义 列配置内就地定义
动态列场景 插槽需提前定义,灵活性一般 可随列配置动态生成,灵活性更高
可读性 结构清晰,适合复杂模板 逻辑与列定义在一起,适合简单渲染
能力 等价 等价

两者能力上没有差异,选择主要看项目技术栈与团队习惯。若列是静态的,模板插槽更直观;若列由接口或配置动态生成,JSX 插槽更容易随列一起构造。

渲染性能:三种方式的取舍

各自适用场景

方式 性能 灵活性 适用场景
提前转换数据 data: [{...}] 最优 低 数据结构固定,展示逻辑简单,追求极致性能
formatter 格式化 优 中 纯文本格式化,如性别、状态码转中文
slots 自定义插槽 较差 最高 需要渲染组件、图片、按钮、多元素组合
  • data 预转换:在请求返回后立即把展示字段算好,表格渲染时直接取用。性能最好,但数据变化时需重新转换。
  • formatter:字段值变化时触发,适合简单的值映射。比插槽轻量,但不支持渲染组件。
  • slots:每次渲染都会实时调用,灵活性最高但开销最大。数据量大、单元格内容复杂时需注意性能。
    建议:能用 formatter 解决的就不要用插槽;必须渲染组件(图片、按钮等)时才使用插槽。若插槽内逻辑较重,可考虑提前算好部分数据放入行对象,减少插槽内的计算。

关键配置参数

配置项 类型 说明
列 slots.default String / Function 模板插槽填插槽名字符串;JSX 插槽填渲染函数
插槽名 String 建议遵循 {field}_default 命名,便于识别
slots.default 参数 Object 含 row、column、rowIndex、columnIndex、$grid
posted @ 2026-11-11 16:08  独行者r2  阅读(13)  评论(0)    收藏  举报