Spreadsheet 表格编辑器
A1 风格可编辑网格 —— 多选、键盘导航(方向键 / Tab / Enter / F2 / Delete)、Cmd+C/V 与系统剪贴板互通。
基础用法
v-model 绑定一个以 A1 字符串为 key 的扁平 Record<string, string>。组件给你一张可编辑的网格:
- 单击一格 → 选中
- 拖拽 / Shift+点击 → 选择区域
- 双击 / Enter / F2 → 编辑当前格
- 方向键 / Tab → 移动焦点
- Delete / Backspace → 清空选区
- Cmd/Ctrl + C / X / V → 与系统剪贴板互通 TSV
背景
单击选中、双击编辑、方向键移动、Tab/Enter 确认;Cmd/Ctrl + C / V 在选区与剪贴板间复制粘贴 TSV。
A
B
C
D
E
1
产品
区域
销量
2
A
华北
120
3
B
华东
230
4
C
华南
180
5
6
7
8
9
10
<script setup lang="ts">
import { ref } from 'vue';
import { CfSpreadsheet } from '@chufix-design/vue';
const data = ref<Record<string, string>>({
A1: '产品',
B1: '区域',
C1: '销量',
A2: 'A',
B2: '华北',
C2: '120',
A3: 'B',
B3: '华东',
C3: '230',
A4: 'C',
B4: '华南',
C4: '180',
});
</script>
<template>
<p style="margin: 0 0 8px; color: var(--fg-3); font-size: 12px;">
单击选中、双击编辑、方向键移动、Tab/Enter 确认;Cmd/Ctrl + C / V 在选区与剪贴板间复制粘贴 TSV。
</p>
<CfSpreadsheet v-model="data" :rows="10" :cols="5" />
</template> <script setup>
import { ref } from 'vue';
import { CfSpreadsheet } from '@chufix-design/vue';
const data = ref<Record<string, string>>({
A1: '产品',
B1: '区域',
C1: '销量',
A2: 'A',
B2: '华北',
C2: '120',
A3: 'B',
B3: '华东',
C3: '230',
A4: 'C',
B4: '华南',
C4: '180',
});
</script>
<template>
<p style="margin: 0 0 8px; color: var(--fg-3); font-size: 12px;">
单击选中、双击编辑、方向键移动、Tab/Enter 确认;Cmd/Ctrl + C / V 在选区与剪贴板间复制粘贴 TSV。
</p>
<CfSpreadsheet v-model="data" :rows="10" :cols="5" />
</template> 与外部表格互通
剪贴板格式是标准 TSV(tab 分隔的文本),所以可以直接和 Excel / Numbers / Google Sheets 互拷数据:
背景
A
B
C
D
E
1
2
3
4
5
6
7
8
9
10
试试:在 Excel / Numbers / Sheets 选一段复制,到这里 Cmd/Ctrl+V 粘贴;反向 Cmd/Ctrl+C 也能拷出去。
<script setup lang="ts">
import { ref } from 'vue';
import { CfSpreadsheet, CfButton, toast, rangeToTSV } from '@chufix-design/vue';
const data = ref<Record<string, string>>({});
function loadSample() {
data.value = {
A1: 'date', B1: 'cpu', C1: 'mem',
A2: '2026-05-01', B2: '0.42', C2: '0.61',
A3: '2026-05-02', B3: '0.51', C3: '0.65',
A4: '2026-05-03', B4: '0.66', C4: '0.72',
A5: '2026-05-04', B5: '0.49', C5: '0.69',
A6: '2026-05-05', B6: '0.58', C6: '0.71',
};
}
async function exportAll() {
const tsv = rangeToTSV(data.value, {
start: { col: 0, row: 0 },
end: { col: 4, row: 9 },
});
await navigator.clipboard.writeText(tsv);
toast({ type: 'success', message: 'TSV 已复制到剪贴板' });
}
</script>
<template>
<div style="display: flex; gap: 8px; margin-bottom: 8px;">
<CfButton size="sm" @click="loadSample">载入样例数据</CfButton>
<CfButton size="sm" variant="tertiary" @click="exportAll">导出全部为 TSV</CfButton>
</div>
<CfSpreadsheet v-model="data" :rows="10" :cols="5" :col-width="140" />
<p style="margin-top: 8px; color: var(--fg-3); font-size: 12px;">
试试:在 Excel / Numbers / Sheets 选一段复制,到这里 Cmd/Ctrl+V 粘贴;反向 Cmd/Ctrl+C 也能拷出去。
</p>
</template> <script setup>
import { ref } from 'vue';
import { CfSpreadsheet, CfButton, toast, rangeToTSV } from '@chufix-design/vue';
const data = ref<Record<string, string>>({});
function loadSample() {
data.value = {
A1: 'date', B1: 'cpu', C1: 'mem',
A2: '2026-05-01', B2: '0.42', C2: '0.61',
A3: '2026-05-02', B3: '0.51', C3: '0.65',
A4: '2026-05-03', B4: '0.66', C4: '0.72',
A5: '2026-05-04', B5: '0.49', C5: '0.69',
A6: '2026-05-05', B6: '0.58', C6: '0.71',
};
}
async function exportAll() {
const tsv = rangeToTSV(data.value, {
start: { col: 0, row: 0 },
end: { col: 4, row: 9 },
});
await navigator.clipboard.writeText(tsv);
toast({ type: 'success', message: 'TSV 已复制到剪贴板' });
}
</script>
<template>
<div style="display: flex; gap: 8px; margin-bottom: 8px;">
<CfButton size="sm" @click="loadSample">载入样例数据</CfButton>
<CfButton size="sm" variant="tertiary" @click="exportAll">导出全部为 TSV</CfButton>
</div>
<CfSpreadsheet v-model="data" :rows="10" :cols="5" :col-width="140" />
<p style="margin-top: 8px; color: var(--fg-3); font-size: 12px;">
试试:在 Excel / Numbers / Sheets 选一段复制,到这里 Cmd/Ctrl+V 粘贴;反向 Cmd/Ctrl+C 也能拷出去。
</p>
</template> API
| Prop | 类型 | 默认 | 说明 |
|---|---|---|---|
modelValue (Vue) / modelValue + onChange (React) | Record<string, string> | {} | A1 键值映射 |
rows | number | 20 | 行数 |
cols | number | 10 | 列数 |
colWidth | number | 120 | 单列像素宽度 |
rowHeight | number | 28 | 单行像素高度 |
rowHeaderWidth | number | 44 | 行号栏宽度 |
readonly | boolean | false | 只读模式(禁止编辑 / 删除 / 粘贴) |
disableClipboard | boolean | false | 关闭 Cmd+C / V 与系统剪贴板的桥接 |
caption | string | — | 顶部说明 |
size | 'sm' | 'md' | 'lg' | 'md' | 字号档位 |
事件:
- Vue:
@update:modelValue(next)/@cell-change({ cell, value })/@selection-change(range) - React:
onChange/onCellChange/onSelectionChange
工具函数
import { toA1, colLetter, rangeToTSV, tsvToData } from '@chufix-design/vue';
toA1(0, 0); // 'A1'
colLetter(27); // 'AB'
rangeToTSV(data, { start: { col: 0, row: 0 }, end: { col: 2, row: 4 } });
tsvToData('1\t2\n3\t4', { col: 0, row: 0 }, { cols: 10, rows: 20 });
剪贴板桥接和工具函数都是纯函数,可以脱离组件直接复用。
键盘表
| 按键 | 行为 |
|---|---|
← / → / ↑ / ↓ | 移动选区焦点(按住 Shift 扩展选区) |
Tab / Shift+Tab | 横向移动 |
Enter / F2 | 编辑当前格;编辑中 Enter 提交并下移 |
Esc | 取消正在进行的编辑 |
Delete / Backspace | 清空选区内的所有单元格 |
| 任意可见字符 | 直接进入编辑态并以该字符开头 |
Cmd/Ctrl + C / X / V | 与系统剪贴板互通 TSV |
Cmd/Ctrl + A | 全选 |
反馈与讨论
Spreadsheet 表格编辑器 的讨论