Zimo 530a6f4b65 fix表格判断是否存在子表头判断方法 2 天之前
..
README.md c1c213120e 调整运营会议表单 2 天之前
ZmTableColumn.vue ce75df3df1 调整表格css变量 2 天之前
ZmTableColumnSettingTree.vue ce75df3df1 调整表格css变量 2 天之前
index.vue 530a6f4b65 fix表格判断是否存在子表头判断方法 2 天之前
token.ts 6eb7aef0b2 调整运营会议 2 天之前
useTableComponents.ts e95766cd10 1 3 月之前

README.md

ZmTable

ZmTable 是基于 Element Plus el-table / el-table-column 封装的业务表格组件,主要补了这些能力:

  • 默认统一表格视觉样式。
  • 自动按内容计算列宽,并支持全局限制最大宽度。
  • 表格级 align 统一控制列对齐方式。
  • 列头内置排序、筛选按钮,但排序和筛选逻辑交给调用方自定义。
  • 操作列可以开启列设置面板,支持列显隐、固定左/右、拖拽排序。
  • 支持多级表头,子级表头只能在自己的父级分组内排序。
  • 样式通过少量 CSS 变量开放给外部调整。

文件说明

文件 作用
index.vue 表格主体,负责数据、默认样式、列配置收集、列顺序/显隐/固定渲染。
ZmTableColumn.vue 列组件,负责列头按钮、排序、筛选、操作列设置入口、列宽计算。
ZmTableColumnSettingTree.vue 列设置面板里的递归树,负责拖拽排序、显隐、固定按钮。
token.ts 表格内部依赖注入类型和 key。
useTableComponents.ts 给 TS 泛型使用的便捷导出。

基础用法

推荐在页面里通过 useTableComponents<T>() 获取泛型组件,这样 proprow 会更容易获得类型提示。

<script setup lang="ts">
import { useTableComponents } from '@/components/ZmTable/useTableComponents'

interface ListItem {
  id: number
  name: string
  status: string
}

const loading = ref(false)
const list = ref<ListItem[]>([])

const { ZmTable, ZmTableColumn } = useTableComponents<ListItem>()
</script>

<template>
  <ZmTable :data="list" :loading="loading">
    <ZmTableColumn type="index" label="序号" :width="60" />
    <ZmTableColumn prop="name" label="名称" />
    <ZmTableColumn prop="status" label="状态">
      <template #default="{ row }">
        <el-tag>{{ row.status }}</el-tag>
      </template>
    </ZmTableColumn>
  </ZmTable>
</template>

也可以直接用小写组件名:

<zm-table :data="list" :loading="loading">
  <zm-table-column prop="name" label="名称" />
</zm-table>

ZmTable Props

ZmTable 继承大部分 Element Plus TableProps,下面是额外增加或重点关注的属性。

属性 类型 默认值 说明
data T[] 必填 表格数据。
loading boolean 必填 表格 loading 状态。
align 'left' \| 'center' \| 'right' 'center' 全局列对齐方式。普通列会使用它;开启排序、筛选、操作列时,列头会优先左对齐。
columnMaxWidth number 360 自动计算列宽时的最大宽度。
customClass boolean false true 时不挂载默认 .zm-table class,也就不会使用组件默认样式变量。
showBorder boolean false 控制组件自己的边框显示样式。
showOverflowTooltip boolean true 继承自 Element Plus。想让文字换行时传 false,再配合页面 CSS 覆盖 .cell 的换行样式。

组件内部默认还会给 Element Plus 表格设置这些值:

{
  size: 'default',
  stripe: true,
  border: true,
  highlightCurrentRow: true,
  showOverflowTooltip: true,
  scrollbarAlwaysOn: true,
  tooltipOptions: {
    popperClass: 'max-w-120'
  }
}

ZmTableColumn Props

ZmTableColumn 继承大部分 Element Plus TableColumnCtx,下面是额外增加或重点关注的属性。

属性 类型 默认值 说明
prop keyof T \| string - 字段名,也会作为列设置 key 的优先来源。
action boolean false 标记为操作列,并在表头显示列设置按钮。操作列本身不会进入列设置列表。
hideInColumnSettings boolean false 不显示在列设置面板里,适合序号列、选择列等固定功能列。
isParent boolean false 标记当前列是多级表头父级。需要控制子级列排序/显隐/固定时必须加。
zmSortable boolean false 显示排序按钮。组件只维护/展示排序状态,具体排序逻辑由调用方处理。
zmFilterable boolean false 显示筛选按钮和 popover。筛选内容和筛选逻辑由调用方通过 #filter 自定义。
sortOrder 'asc' \| 'desc' \| null - 外部受控排序状态。传了这个值之后,组件不会自己保存排序状态。
defaultSortOrder 'asc' \| 'desc' \| null null 非受控模式下的默认排序状态。
zmSortMethod (prop, order) => void - 点击排序按钮后调用。
filterActive boolean - 强制控制筛选按钮激活态。不传时根据 filterModelValue 自动判断。
filterModelValue any - 筛选值,可用 v-model:filter-model-value 双向绑定。
realValue (...args) => any - 获取真实展示值。自动算宽时会优先使用它;配合 coverFormatter 时也会作为 formatter。
coverFormatter boolean false true 时,把 realValue 作为 Element Plus 的 formatter 使用。

排序

开启 zm-sortable 后,表头只显示排序按钮和排序状态图标:

  • 未排序:i-lucide:arrow-up-down
  • 升序:i-lucide:arrow-up-narrow-wide
  • 降序:i-lucide:arrow-down-wide-narrow

点击顺序是:

null -> asc -> desc -> null

非受控用法:

<ZmTableColumn prop="meetingDate" label="会议日期" zm-sortable :zm-sort-method="handleSort" />
function handleSort(prop: string, order: 'asc' | 'desc' | null) {
  query.value.sortField = prop
  query.value.sortOrder = order
  getList()
}

受控用法:

<ZmTableColumn
  prop="meetingDate"
  label="会议日期"
  zm-sortable
  v-model:sort-order="meetingDateOrder"
  @sort-change="handleSortChange"
/>
const meetingDateOrder = ref<'asc' | 'desc' | null>(null)

function handleSortChange(payload: { prop: string; order: 'asc' | 'desc' | null }) {
  query.value.sortField = payload.prop
  query.value.sortOrder = payload.order
  getList()
}

筛选

开启 zm-filterable 后,表头只显示筛选按钮。popover 里面展示什么、怎么过滤,都由调用方写在 #filter 插槽里。

<ZmTableColumn
  prop="status"
  label="状态"
  zm-filterable
  v-model:filter-model-value="query.status"
  @filter-visible-change="handleFilterVisibleChange"
>
  <template #filter="{ filterModelValue, updateFilterModelValue, close }">
    <div class="p-2">
      <el-select
        :model-value="filterModelValue"
        placeholder="请选择状态"
        clearable
        class="w-full"
        @update:model-value="updateFilterModelValue"
      >
        <el-option label="启用" value="enable" />
        <el-option label="停用" value="disable" />
      </el-select>

      <div class="mt-2 flex justify-end gap-2">
        <el-button size="small" @click="updateFilterModelValue(undefined)">清空</el-button>
        <el-button
          size="small"
          type="primary"
          @click="
            () => {
              handleQuery()
              close()
            }
          "
        >
          确定
        </el-button>
      </div>
    </div>
  </template>
</ZmTableColumn>

#filter 插槽会收到这些常用参数:

参数 说明
prop 当前列字段名。
filterModelValue 当前筛选值。
updateFilterModelValue(value) 更新筛选值,会触发 update:filterModelValue
close() 关闭 popover。
setVisible(visible) 手动控制 popover 显隐。

筛选按钮是否高亮:

  • 传了 filterActive 时,以 filterActive 为准。
  • 没传 filterActive 时,组件会根据 filterModelValue 是否有值自动判断。

操作列和列设置

给操作列加 action,表头会显示设置按钮。

<ZmTable :data="list" :loading="loading">
  <ZmTableColumn prop="name" label="名称" />
  <ZmTableColumn prop="status" label="状态" />

  <ZmTableColumn label="操作" width="120" fixed="right" action>
    <template #default="{ row }">
      <el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
    </template>
  </ZmTableColumn>
</ZmTable>

列设置面板支持:

  • 拖拽调整列顺序。
  • 显示 / 隐藏列。
  • 固定到左侧 / 固定到右侧 / 取消固定。
  • 重置为初始列配置。

列设置 key 的优先级:

columnKey -> prop -> type -> label -> column-${index}

建议动态列、同名列、没有 prop 的列都手动传 column-key,避免 key 不稳定。

<ZmTableColumn column-key="custom-action" label="自定义列">
  ...
</ZmTableColumn>

多级表头

Element Plus 原生多级表头可以直接写:

<ZmTableColumn label="累计" is-parent>
  <ZmTableColumn prop="totalGasInjection" label="注气量" />
  <ZmTableColumn prop="totalWaterInjection" label="注水量" />
  <ZmTableColumn prop="totalPower" label="用电量" />
</ZmTableColumn>

如果想让列设置面板识别并控制子级表头,需要给父级列加 is-parent

子级列拖拽时只能在自己的父级分组内排序。比如 累计 下面有三个子列,这三个子列只能在 累计 里面互相调整,不能被拖到其他父级外面。

对齐优先级

普通列对齐优先级:

列自己的 align -> ZmTable 的 align -> 默认 center

开启了下面任意能力时,表头会优先左对齐,方便标题和按钮同时展示:

  • action
  • zm-sortable
  • zm-filterable

示例:

<ZmTable :data="list" :loading="loading" align="right">
  <ZmTableColumn prop="amount" label="金额" />
  <ZmTableColumn prop="name" label="名称" align="left" />
  <ZmTableColumn prop="date" label="日期" zm-sortable />
</ZmTable>

上面例子里:

  • amount 使用表格全局 right
  • name 使用列自己的 left
  • date 因为开启了排序,表头优先 left

自动列宽

每个有 prop 的列会根据表头和当前数据自动计算 minWidth

计算逻辑大致是:

  • 取表头文字宽度。
  • 取当前页数据里该列内容的最大文字宽度。
  • 如果列头有排序/筛选按钮,会额外加上按钮宽度。
  • 最终宽度不会超过 ZmTablecolumnMaxWidth,默认是 360

    <ZmTable :data="list" :loading="loading" :column-max-width="480">
    <ZmTableColumn prop="description" label="描述" />
    </ZmTable>
    

如果展示值不是原始字段值,建议传 real-value,这样自动宽度会按真实显示值计算。

<ZmTableColumn
  prop="meetingDate"
  label="会议日期"
  cover-formatter
  :real-value="(row) => dayjs(row.meetingDate).format('YYYY-MM-DD')"
/>

插槽

ZmTable 会透传 Element Plus 表格的大部分插槽,默认插槽用于放 ZmTableColumn

ZmTableColumn 会透传 Element Plus 列的大部分插槽:

<ZmTableColumn prop="status" label="状态">
  <template #default="{ row }">
    <el-tag>{{ row.status }}</el-tag>
  </template>
</ZmTableColumn>

如果自定义了 #header,组件内置的排序、筛选、设置按钮不会自动渲染,需要调用方自己处理表头内容。

Expose

ZmTable 暴露了内部 Element Plus 表格实例:

<script setup lang="ts">
const tableRef = ref()

function clearSelection() {
  tableRef.value?.elTableRef?.clearSelection()
}
</script>

<template>
  <ZmTable ref="tableRef" :data="list" :loading="loading" />
</template>

CSS 变量

默认样式挂在 .zm-table 上。外部可以通过 class 覆盖变量:

<ZmTable class="meeting-table" :data="list" :loading="loading" />
.meeting-table {
  --zm-table-font-size: 13px;
  --zm-table-header-bg: #f3f6fb;
  --zm-table-cell-height: 44px;
}

表格变量

变量 默认值 说明
--zm-table-font-family inherit 表格字体。
--zm-table-font-size 12px 表格基础字号。
--zm-table-text-color #40546d 普通文字颜色。
--zm-table-strong-text-color #24364d body 单元格文字颜色。
--zm-table-row-font-weight 500 body 单元格字重。
--zm-table-bg var(--el-bg-color) 表格背景。
--zm-table-border-color #e7edf4 表格外边框颜色。
--zm-table-radius 10px 表格圆角。
--zm-table-header-bg var(--el-fill-color-extra-light, #f7f9fc) 表头背景。
--zm-table-header-text-color var(--el-text-color-secondary, #6b7f99) 表头文字颜色。
--zm-table-header-border-color var(--zm-table-border-color) 表头边框颜色。
--zm-table-header-cell-height 36px 普通表头高度。
--zm-table-header-group-cell-height 42px 多级表头父级高度。
--zm-table-header-font-size var(--zm-table-font-size) 表头字号。
--zm-table-header-font-weight 600 表头字重。
--zm-table-header-line-height 16px 表头行高。
--zm-table-header-icon-btn-size 18px 表头图标按钮尺寸。
--zm-table-header-icon-btn-color #8aa0b8 表头图标默认颜色。
--zm-table-header-icon-btn-radius 4px 表头图标按钮圆角。
--zm-table-header-icon-btn-hover-color var(--el-color-primary) 表头图标 hover 颜色。
--zm-table-header-icon-btn-hover-bg var(--el-color-primary-light-9) 表头图标 hover 背景。
--zm-table-header-icon-btn-active-color var(--zm-table-header-icon-btn-hover-color) 表头图标激活颜色。
--zm-table-header-icon-btn-active-bg var(--zm-table-header-icon-btn-hover-bg) 表头图标激活背景。
--zm-table-header-icon-size 16px 表头图标尺寸。
--zm-table-row-border-color #edf2f7 body 单元格边框颜色。
--zm-table-stripe-bg #fcfdff 斑马纹背景。
--zm-table-hover-bg #f5f9ff 行 hover 背景。
--zm-table-current-bg #eef6ff 当前行背景。
--zm-table-cell-height 38px body 单元格高度。
--zm-table-cell-padding-x 13px body 单元格左右 padding。
--zm-table-cell-first-padding-left calc(var(--zm-table-cell-padding-x) + 3px) 每行第一个单元格左 padding。
--zm-table-cell-last-padding-right var(--zm-table-cell-first-padding-left) 每行最后一个单元格右 padding。
--zm-table-cell-line-height 18px body 单元格行高。
--zm-table-empty-min-height 148px 空状态最小高度。
--zm-table-empty-bg var(--zm-table-bg) 空状态背景。
--zm-table-empty-text-font-size var(--zm-table-font-size) 空状态文字字号。
--zm-table-empty-text-color var(--el-text-color-secondary) 空状态文字颜色。
--zm-table-scrollbar-size 7px 滚动条尺寸。
--zm-table-scrollbar-thumb-bg #b8c5d6 滚动条滑块颜色。

列设置变量

列设置面板 popover 使用 .zm-table-column-setting-popper,可以全局覆盖,也可以在页面样式中覆盖。

变量 默认值 说明
--zm-table-column-setting-font-size var(--zm-table-font-size, 12px) 设置面板字号。
--zm-table-column-setting-text-color var(--el-text-color-regular) 设置面板文字颜色。
--zm-table-column-setting-border-color var(--el-border-color) 设置面板分割线颜色。
--zm-table-column-setting-hover-bg var(--el-fill-color-lighter) 设置项 hover 背景。
--zm-table-column-setting-radius 6px 设置项圆角。
--zm-table-column-setting-gap 4px 设置项纵向间距。
--zm-table-column-setting-max-height 360px 设置面板最大高度。
--zm-table-column-setting-row-height 32px 一级设置项高度。
--zm-table-column-setting-child-row-height 30px 子级设置项高度。
--zm-table-column-setting-item-font-weight 400 普通设置项字重。
--zm-table-column-setting-group-font-weight 600 分组设置项字重。
--zm-table-column-setting-icon-btn-size 22px 设置项图标按钮尺寸。
--zm-table-column-setting-icon-size 15px 设置项图标尺寸。
--zm-table-column-setting-icon-color #8aa0b8 设置项图标默认颜色。
--zm-table-column-setting-icon-active-color var(--el-color-primary) 设置项图标激活颜色。
--zm-table-column-setting-icon-active-bg var(--el-color-primary-light-9) 设置项图标激活背景。
--zm-table-column-setting-ghost-bg var(--el-color-primary-light-9) 拖拽占位背景。
--zm-table-column-setting-ghost-opacity 0.55 拖拽占位透明度。

自动宽度测量变量

自动算宽时会创建隐藏文本节点测量文字宽度,可以用这两个变量控制测量字体:

变量 默认值 说明
--zm-table-column-width-measure-font-size --zm-table-font-size 或当前表格字号 测量文字宽度时的字号。
--zm-table-column-width-measure-font-family 当前表格字体或 Noto Sans SC 测量文字宽度时的字体。

文字换行

默认 showOverflowTooltiptrue,单元格会走 Element Plus 的溢出 tooltip。想关闭 tooltip 并让内容自动换行,可以这样写:

<ZmTable class="wrap-table" :data="list" :loading="loading" :show-overflow-tooltip="false">
  <ZmTableColumn prop="description" label="描述" />
</ZmTable>
.wrap-table {
  :deep(.el-table__body .cell) {
    overflow: visible;
    text-overflow: initial;
    white-space: normal;
    word-break: break-word;
  }
}

注意事项

  • 列设置只识别 ZmTableColumn,不要在默认插槽里混入其他会渲染成列的组件。
  • 多级表头想被设置面板递归识别,需要在父级列上加 is-parent
  • 动态列建议手动传 column-key,否则列顺序和显隐状态可能因为 key 变化而重置。
  • 排序和筛选按钮只负责 UI 状态,不会自动修改 data 或请求接口。
  • 如果传了自定义 #header,内置排序、筛选、设置按钮不会出现。
  • customClass=true 会关闭默认 .zm-table 样式,相关 CSS 变量也不会自动生效。