Preview Updated 2026-05-10

ReorderTable 重排表格

行拖拽重排的轻量表格。grid 布局、首列固定拖拽手柄、邻居行 CSS transform 让位、Esc 取消。

English translation pending This page hasn't been translated yet — falling back to Chinese. PRs welcome on GitHub.

基础用法

CfReorderTable 是行拖拽重排的独立组件,不是 CfTable 的子类。它用 CSS Grid 布局而非 <table> 标签 — 因为 <tr> 上做 transform 不稳,grid 行就没有这个限制。需要功能更全的表格(排序 / 筛选 / 列冻结 / 分组)请用 CfTableCfDataGrid,需要可重排行的简洁场景用这一个。

columns 数组定义列;首列自动是拖拽手柄,无需在 columns 里声明。富文本单元格用 cell-<key> 作用域插槽(Vue)或 column.render (React)。

背景 视口
src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
import { CfReorderTable, type ReorderColumn } from '@chufix-design/vue';

interface ServiceRow {
  id: string;
  name: string;
  region: string;
  p99: string;
  status: 'healthy' | 'degraded' | 'down';
}

const rows = ref<ServiceRow[]>([
  { id: 'auth', name: 'auth-service', region: 'us-east-1', p99: '38 ms', status: 'healthy' },
  { id: 'order', name: 'order-service', region: 'us-east-1', p99: '92 ms', status: 'degraded' },
  { id: 'pay', name: 'pay-service', region: 'eu-west-1', p99: '120 ms', status: 'degraded' },
  { id: 'mail', name: 'mail-service', region: 'us-west-2', p99: '210 ms', status: 'down' },
  { id: 'cdn', name: 'cdn-edge', region: 'global', p99: '14 ms', status: 'healthy' },
]);

const columns: ReorderColumn<ServiceRow>[] = [
  { key: 'name', label: '服务' },
  { key: 'region', label: '区域', width: '120px' },
  { key: 'p99', label: 'P99', width: '90px', align: 'end' },
  { key: 'status', label: '状态', width: '110px' },
];
</script>
<template>
  <CfReorderTable v-model:rows="rows" :columns="columns" row-key="id" striped>
    <template #cell-status="{ value }">
      <span class="status-pill" :data-tone="value">{{ value }}</span>
    </template>
  </CfReorderTable>
</template>
<style scoped>
.status-pill {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: var(--r-pill);
  font-size: var(--t-12);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.status-pill[data-tone='healthy'] {
  background: var(--status-success-soft);
  color: var(--status-success);
}
.status-pill[data-tone='degraded'] {
  background: var(--status-warning-soft);
  color: var(--status-warning);
}
.status-pill[data-tone='down'] {
  background: var(--status-error-soft);
  color: var(--status-error);
}
</style>
<script setup>
import { ref } from 'vue';
import { CfReorderTable } from '@chufix-design/vue';

const rows = ref<ServiceRow[]>([
  { id: 'auth', name: 'auth-service', region: 'us-east-1', p99: '38 ms', status: 'healthy' },
  { id: 'order', name: 'order-service', region: 'us-east-1', p99: '92 ms', status: 'degraded' },
  { id: 'pay', name: 'pay-service', region: 'eu-west-1', p99: '120 ms', status: 'degraded' },
  { id: 'mail', name: 'mail-service', region: 'us-west-2', p99: '210 ms', status: 'down' },
  { id: 'cdn', name: 'cdn-edge', region: 'global', p99: '14 ms', status: 'healthy' },
]);

const columns= [
  { key: 'name', label: '服务' },
  { key: 'region', label: '区域', width: '120px' },
  { key: 'p99', label: 'P99', width: '90px', align: 'end' },
  { key: 'status', label: '状态', width: '110px' },
];
</script>
<template>
  <CfReorderTable v-model:rows="rows" :columns="columns" row-key="id" striped>
    <template #cell-status="{ value }">
      <span class="status-pill" :data-tone="value">{{ value }}</span>
    </template>
  </CfReorderTable>
</template>
<style scoped>
.status-pill {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: var(--r-pill);
  font-size: var(--t-12);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.status-pill[data-tone='healthy'] {
  background: var(--status-success-soft);
  color: var(--status-success);
}
.status-pill[data-tone='degraded'] {
  background: var(--status-warning-soft);
  color: var(--status-warning);
}
.status-pill[data-tone='down'] {
  background: var(--status-error-soft);
  color: var(--status-error);
}
</style>
import { useState } from 'react';
import { CfReorderTable } from '@chufix-design/react';

export default function Demo() {
  interface ServiceRow {
    id: string;
    name: string;
    region: string;
    p99: string;
    status: 'healthy' | 'degraded' | 'down';
  }

  const [rows, setRows] = useState<ServiceRow[]>([
    { id: 'auth', name: 'auth-service', region: 'us-east-1', p99: '38 ms', status: 'healthy' },
    { id: 'order', name: 'order-service', region: 'us-east-1', p99: '92 ms', status: 'degraded' },
    { id: 'pay', name: 'pay-service', region: 'eu-west-1', p99: '120 ms', status: 'degraded' },
    { id: 'mail', name: 'mail-service', region: 'us-west-2', p99: '210 ms', status: 'down' },
    { id: 'cdn', name: 'cdn-edge', region: 'global', p99: '14 ms', status: 'healthy' },
  ]);

  const columns: ReorderColumn<ServiceRow>[] = [
    { key: 'name', label: '服务' },
    { key: 'region', label: '区域', width: '120px' },
    { key: 'p99', label: 'P99', width: '90px', align: 'end' },
    { key: 'status', label: '状态', width: '110px' },
  ];
  return (
    <>
      <CfReorderTable rows={rows} onRowsChange={setRows} columns={columns} row-key="id" striped>
            <span className="status-pill" dataTone={value}>{value}</span>
    </>
  );
}
import { useState } from 'react';
import { CfReorderTable } from '@chufix-design/react';

export default function Demo() {

  const [rows, setRows] = useState<ServiceRow[]>([
    { id: 'auth', name: 'auth-service', region: 'us-east-1', p99: '38 ms', status: 'healthy' },
    { id: 'order', name: 'order-service', region: 'us-east-1', p99: '92 ms', status: 'degraded' },
    { id: 'pay', name: 'pay-service', region: 'eu-west-1', p99: '120 ms', status: 'degraded' },
    { id: 'mail', name: 'mail-service', region: 'us-west-2', p99: '210 ms', status: 'down' },
    { id: 'cdn', name: 'cdn-edge', region: 'global', p99: '14 ms', status: 'healthy' },
  ]);

  const columns= [
    { key: 'name', label: '服务' },
    { key: 'region', label: '区域', width: '120px' },
    { key: 'p99', label: 'P99', width: '90px', align: 'end' },
    { key: 'status', label: '状态', width: '110px' },
  ];
  return (
    <>
      <CfReorderTable rows={rows} onRowsChange={setRows} columns={columns} row-key="id" striped>
            <span className="status-pill" dataTone={value}>{value}</span>
    </>
  );
}

API

Props

属性类型默认说明
rowsT[]数据行
columnsReorderColumn<T>[]列定义
rowKeykeyof T | ((row, index) => string | number)行 key
disabledbooleanfalse禁用拖拽
handleWidthstring'36px'首列手柄宽度
stripedbooleanfalse隔行变色
animationnumber180邻居复位过渡 ms
thresholdnumber4起拖位移 px

ReorderColumn

字段类型说明
keystring列名 / 取值键
labelstring表头文字
widthstringgrid-template 值,如 '120px' / '1fr'
align'start' | 'center' | 'end'单元格水平对齐
render(row, index) => ReactNodeReact 自定义渲染;Vue 用 cell-<key> 插槽

Events

事件载荷说明
update:rowsT[]新顺序
reorder{ from, to, rows }提交后触发

反馈与讨论

ReorderTable 重排表格 · Discussion

0
0 / 600
正在加载评论...