Skip to content

PcTable 通用表格

PcTable 是基于 Element Plus Table 封装的业务表格组件,用于管理后台列表页。支持接口自动请求、外部数据传入、分页、多选列、序号列、自定义列渲染与操作列。

基础用法

由父组件维护数据时,直接传入 tableList 即可渲染。列配置的 prop 会对应同名插槽,可用于自定义状态列、操作列等。

loading

自动请求

传入 requestApi 后,组件负责请求数据、维护 loading 与分页。接口入参为 { pageNo, pageSize, ...reqParams },返回结构需为 { data: { records, total } }。配合 useTablePage 管理表格引用,可通过 requestTable('reset' | 'default') 主动刷新。

loading

多选与序号列

设置 selection 显示多选列,typeIndex 显示序号列。可通过 selectable 控制某行勾选框是否可用,并监听 selection-change 获取选中项。

loading

列渲染

单元格内容有三种渲染方式:默认显示 row[prop];使用 #[prop] 插槽自定义;或在列配置里用 render 函数返回 VNode。表头可用 #header-[prop] 插槽自定义。

loading

与 PcSearch 联动

搜索区使用 PcSearch,推荐用 useTablePage 统一管理 tableRef / searchRef,在 request 事件里调用 requestTable() 刷新数据并回到第一页。

loading

行拖拽排序

开启 row-draggable 后可拖拽行来调整顺序。该能力基于 sortablejs 实现,但不打进组件包,需使用方自行安装并在 install 阶段注入,避免与宿主应用重复打包:

ts
// main.ts
import Sortable from "sortablejs" // 使用方自行 npm install sortablejs
import PcTable from "@sud-web/vue-ui"
app.use(PcTable, { sortable: Sortable })
loading

拖拽把手(推荐)

默认整行都可抓取拖拽。若希望只有某个图标能起手(更贴近后台表格习惯),给该列配置加 drag: true:该列单元格会渲染抓手图标,Sortable 自动切到 handle 模式,只有抓住图标才能拖拽。

ts
const columns = [
  { label: '排序', prop: 'sort', width: 90, drag: true }, // 该列显示抓手
  { label: '名称', prop: 'name', minWidth: 160 }
]

抓手图标可用 #drag-handle 插槽整体替换(作用域为 { row, column, $index });不传则用内置默认图标:

vue
<PcTable :colum-list="columns" row-draggable @row-drag-end="onRowDragEnd">
  <template #drag-handle>
    <el-icon><Rank /></el-icon>
  </template>
</PcTable>

drag: true 需配合 row-draggable 才生效(row-draggable 仍是总开关,负责注入 Sortable 与抛 row-drag-end)。也可用 sortable-options.handle 自定义 handle 选择器,传入后以你的值为准。

落点提示线

拖拽时组件内置了「落点插入线」样式(行顶一条线 = 插入边界,方向唯一、不再是含糊的整块高亮),无需额外写 CSS。线的颜色用 drop-line-color 配置(默认取主题色 --el-color-primary):

vue
<PcTable :colum-list="columns" row-draggable drop-line-color="#f56c6c" ... />

想换回整块或自定义样式,可用 sortable-options.ghostClass 覆盖内置的 ghostClass

禁止某行拖拽

row-draggable-fn,返回 false 的行会被禁止拖拽:该行不渲染把手图标、也无法起手拖动(其余行照常)。

vue
<PcTable
  :colum-list="columns"
  row-draggable
  :row-draggable-fn="(row) => row.locked !== true"
/>

该能力只阻止「被拖动」(作为拖拽源)。若还想让被锁定行的位置在别人拖动时也不被挤动,可再通过 sortable-options.onMove 返回 false 拦截。

交互流程(乐观拖拽 + 后端确认回滚)

组件只负责抛事件、不改数据。拖拽结束抛 row-drag-end,并进入 loading 等待使用方确认:

vue
<template>
  <PcTable
    :table-list="list"
    :colum-list="columns"
    row-draggable
    hide-pagination
    row-key="id"
    @row-drag-end="onRowDragEnd"
  />
</template>

<script setup>
async function onRowDragEnd({ oldIndex, newIndex, row, oldRow, position, done }) {
  try {
    // 推荐「单锚点相对契约」:把 row 插到 oldRow 的前/后,position 组件已算好
    //   position: 'after'=下拖(落在 oldRow 之后)、'before'=上拖(落在 oldRow 之前)
    // 相对意图对并发更稳:别处被人改序也不影响「插到某行前/后」这个语义
    await api.reorder({ id: row.id, anchorId: oldRow.id, position })
    // 成功:更新数据(本地 splice 或 requestData())让新顺序生效
    const next = [...list.value]
    const [moved] = next.splice(oldIndex, 1)
    next.splice(newIndex, 0, moved)
    list.value = next
    done(true)
  } catch {
    done(false) // 失败:组件把行还原回原位,等于拖拽取消
  }
}
</script>
  • 成功:调 done(true),并由使用方更新数据(splicerequestData())驱动渲染出新顺序。
  • 失败:调 done(false),组件把被拖动行还原回拖拽前的位置,并弹出失败提示(ElMessage)。提示文案通过 locale.dragFail 配置,默认「拖拽失败」。
  • done 必须调用,否则 loading 不会结束。

落位精度由组件内部保证:onEnd 里会先还原 sortablejs 造成的 DOM 移动,再交给 Vue 按数据渲染,避免真实 DOM 与虚拟 DOM 错位导致的落位偏移。因此即使不传 row-key 也不会错位、失败也能回滚

何时需要传 row-key

row-key 通过 $attrs 透传给内部 el-table是否需要传取决于是否涉及行身份追踪,而非落位精度

场景是否需要 row-key原因
纯拖拽排序,不含多选/展开,成功后本地 splice 保持同一行对象引用不需要落位由组件的 DOM 还原逻辑保证
拖拽 + selection 多选,且希望重排后勾选状态稳定跟随对应行建议传el-table 默认按行对象引用记录选中,splice 能保持;但一旦 requestData 重新拉取生成新对象,无 row-key 勾选会丢
成功后用 requestData() 从后端重新拉取数据来体现新顺序,并要保持多选/展开必须传新数据是全新对象,el-table 需靠 row-key 把新老行对应起来
含可展开行(expand)或树形数据,拖拽后要保持展开状态必须传展开状态按 row-key 记录
开启跨页保留选中(reserve-selection必须传el-table 该特性本身要求 row-key

一句话:落位靠组件内部的 DOM 还原,不依赖 row-keyrow-key 是为“重排/刷新后仍要正确追踪某一行”(多选、展开、跨页保留)而传的。

API

Attributes

属性说明类型默认值
colum-list列配置列表IColumItem[][]
request-api自动请求接口,入参 { pageNo, pageSize, ...reqParams }(params: any) => Promise<{ data: { records: T[]; total: number } }>
req-params请求时附加的查询参数Record<string, any>
request-immediate挂载后是否立即请求booleantrue
table-list外部传入的数据源(传入后进入手动模式,不再走 request-apiT[]
total外部数据模式下的总条数(不传则取 table-list.lengthnumber
selection是否显示多选列booleanfalse
selectable多选时控制某行勾选框是否可用(row: T, index: number) => boolean
type-index是否显示序号列booleanfalse
last-modify-colu是否显示更新人 / 更新时间快捷列booleantrue
last-modify-name-permission更新人列权限标识string
last-modify-time-permission更新时间列权限标识string
show-action-colu是否显示操作列booleantrue
action-width操作列宽度number180
hide-pagination是否隐藏分页booleanfalse
row-draggable是否开启行拖拽排序(需在 install 时注入 Sortable)booleanfalse
row-draggable-fn控制某行是否可拖拽,返回 false 的行禁止拖拽(不渲染把手、无法起手)(row: T, index: number) => boolean
drop-line-color拖拽落点插入线颜色(内置落点线样式)string--el-color-primary
sortable-options透传给 new Sortable 的额外配置(handleanimationghostClass 等;组件默认已设 filter 让多选框/展开图标不触发拖拽,并用内置 ghostClass 画落点线)Record<string, any>
pagination-size默认每页条数number10
pagination-sizes每页条数选项number[][10, 20, 50, 100]
pagination-layout分页布局string"prev, pager, next, jumper, total, sizes"
table-size表格尺寸"large" | "default" | "small""default"
handle-data接口返回后对 records 的处理函数(data: T[]) => T[]
locale文案覆盖(序号、操作、更新人等)Partial<ITableLocale>

未在上表列出的属性会通过 $attrs 透传给内部的 el-table(如 borderstriperow-key 等)。

v-model

名称说明类型
v-model:page-index当前页码number
v-model:page-size每页条数number

Events

事件名说明回调参数
selection-change多选项变化时触发(rows: T[])
update:selectItems多选项变化时触发(同上,便于 v-model:selectItems(rows: T[])
before-request自动请求发起前触发
table-request-end自动请求结束(成功或失败)后触发
sort-change列排序变化时触发({ column, prop, order })
row-drag-end行拖拽结束时触发(需 row-draggable({ oldIndex, newIndex, row, oldRow, position, list, done })row 为被拖动的行(拖拽前 list[oldIndex])、oldRow 为落点锚点行(拖拽前 list[newIndex])、position 为被拖动行相对 oldRow 的落点(after=下拖、before=上拖,组件已算好,直接用于「插到某行前/后」的后端契约);done(success: boolean) 由使用方在处理完后端后调用:true 保持新位置、false 还原回原位并提示失败

Slots

插槽名说明作用域参数
[prop]自定义对应列的单元格内容{ row, column, $index }
header-[prop]自定义对应列的表头内容{ column, $index }
drag-handle自定义拖拽把手图标(需列配置 drag: true 且开启 row-draggable{ row, column, $index }
action操作列内容{ row, column, $index }

Exposes

通过 ref 获取组件实例后可访问:

名称说明类型
requestData重新请求数据,reset 会回到第一页(type?: "reset" | "default") => void
reload重新请求当前页() => void
total当前数据总条数(只读)number
displayTableList当前渲染的数据列表(只读)ComputedRef<T[]>

类型声明

ts
interface IColumItem {
  label: string
  prop: string
  width?: number
  minWidth?: number
  type?: string
  fixed?: boolean
  align?: "left" | "center" | "right"
  sortable?: boolean
  drag?: boolean // 该列渲染拖拽把手图标(需配合 row-draggable);开启后只有图标能起手拖拽
  /** 第一个参数是注入的 h,第二个参数是 { row, index, column } */
  render?: (h: typeof import("vue").h, params: { row: T; index: number; column: any }) => VNode
}

interface ITableLocale {
  index?: string
  action?: string
  creator?: string
  createTime?: string
  updater?: string
  updateTime?: string
  dragFail?: string // 拖拽失败提示文案,默认「拖拽失败」
}

interface PcTableInstance {
  requestData: (type?: "reset" | "default") => void
  reload: () => void
  displayTableList: any
  /** 当前数据总条数 */
  total: number
}