Appearance
Vue 表身合并
通过 merges 配置表身单元格的 rowspan/colspan 合并。
使用的 API
ts
type Column = {
key: string; // 列标识(必填)
title: string; // 列标题(必填)
width: number; // 列宽(必填)
}
type Options = {
list: T[]; // 数据列表
itemKey: string; // 行唯一标识字段名
estimatedSize: number; // 行预估高度(px)
buffer: number; // 缓冲区行数
merges: MergeCell[]; // 表身合并单元格
border: boolean; // 是否显示边框
showHeader: boolean; // 是否显示表头
highlightSelectRow: boolean; // 高亮选中行
}示例
微应用尚未挂载。
源码
点击查看源码
vue
<template>
<div class="demo-wrapper">
<h3 class="demo-title">Vue 表身合并</h3>
<div class="virt-table-controls">
<button type="button" class="virt-table-btn virt-table-btn-primary" @click="scrollTop">滚动到顶部</button>
<button type="button" class="virt-table-btn virt-table-btn-primary" @click="scrollBottom">滚动到底部</button>
<button type="button" class="virt-table-btn virt-table-btn-warning" @click="scrollRandom">随机滚动</button>
<button type="button" class="virt-table-btn virt-table-btn-success" @click="scrollTo500">滚动到第 500 行</button>
<button
type="button"
class="virt-table-btn"
style="background: #8b5cf6; color: #fff"
@click="toggleMerge"
>
切换合并单元格
</button>
</div>
<div class="status-text">{{ status }}</div>
<div style="width: 800px; height: 600px" class="demo-container">
<VirtTableVue ref="tableRef" :columns="columns" :options="options" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { VirtTableVue, type VueTableColumn } from '@virt-table/vue';
import { faker } from '@faker-js/faker';
import type { VirtTableVueInstance } from '../../virt-table-ref';
const COL_COUNT = 30;
const ROW_COUNT = 1000;
const MERGES = [
{ rowIndex: 2, colIndex: 1, rowspan: 3, colspan: 2 },
{ rowIndex: 5, colIndex: 4, rowspan: 2, colspan: 3 },
{ rowIndex: 7, colIndex: 8, rowspan: 4, colspan: 1 },
{ rowIndex: 10, colIndex: 12, rowspan: 2, colspan: 2 },
{ rowIndex: 12, colIndex: 15, rowspan: 3, colspan: 1 },
{ rowIndex: 15, colIndex: 18, rowspan: 2, colspan: 3 },
{ rowIndex: 18, colIndex: 22, rowspan: 4, colspan: 1 },
{ rowIndex: 20, colIndex: 25, rowspan: 2, colspan: 2 },
{ rowIndex: 23, colIndex: 0, rowspan: 3, colspan: 2 },
{ rowIndex: 26, colIndex: 5, rowspan: 2, colspan: 3 },
{ rowIndex: 28, colIndex: 9, rowspan: 4, colspan: 1 },
{ rowIndex: 31, colIndex: 13, rowspan: 2, colspan: 2 },
{ rowIndex: 34, colIndex: 16, rowspan: 3, colspan: 1 },
{ rowIndex: 36, colIndex: 20, rowspan: 2, colspan: 3 },
{ rowIndex: 39, colIndex: 24, rowspan: 4, colspan: 1 },
{ rowIndex: 42, colIndex: 27, rowspan: 2, colspan: 2 },
{ rowIndex: 45, colIndex: 3, rowspan: 3, colspan: 2 },
{ rowIndex: 47, colIndex: 7, rowspan: 2, colspan: 3 },
{ rowIndex: 50, colIndex: 11, rowspan: 4, colspan: 1 },
{ rowIndex: 53, colIndex: 14, rowspan: 2, colspan: 2 },
{ rowIndex: 55, colIndex: 19, rowspan: 3, colspan: 1 },
{ rowIndex: 58, colIndex: 23, rowspan: 2, colspan: 3 },
{ rowIndex: 61, colIndex: 26, rowspan: 4, colspan: 1 },
{ rowIndex: 64, colIndex: 2, rowspan: 2, colspan: 2 },
{ rowIndex: 66, colIndex: 6, rowspan: 3, colspan: 2 },
{ rowIndex: 69, colIndex: 10, rowspan: 2, colspan: 3 },
{ rowIndex: 72, colIndex: 17, rowspan: 4, colspan: 1 },
{ rowIndex: 75, colIndex: 21, rowspan: 2, colspan: 2 },
{ rowIndex: 77, colIndex: 28, rowspan: 3, colspan: 1 },
{ rowIndex: 80, colIndex: 1, rowspan: 2, colspan: 3 },
{ rowIndex: 83, colIndex: 4, rowspan: 4, colspan: 1 },
{ rowIndex: 86, colIndex: 8, rowspan: 2, colspan: 2 },
{ rowIndex: 88, colIndex: 15, rowspan: 3, colspan: 1 },
{ rowIndex: 91, colIndex: 22, rowspan: 2, colspan: 3 },
{ rowIndex: 94, colIndex: 25, rowspan: 4, colspan: 1 },
{ rowIndex: 97, colIndex: 0, rowspan: 2, colspan: 2 },
{ rowIndex: 100, colIndex: 12, rowspan: 3, colspan: 2 },
{ rowIndex: 105, colIndex: 18, rowspan: 2, colspan: 3 },
{ rowIndex: 110, colIndex: 24, rowspan: 4, colspan: 1 },
{ rowIndex: 115, colIndex: 7, rowspan: 2, colspan: 2 },
{ rowIndex: 120, colIndex: 14, rowspan: 3, colspan: 1 },
{ rowIndex: 125, colIndex: 21, rowspan: 2, colspan: 3 },
{ rowIndex: 130, colIndex: 27, rowspan: 4, colspan: 1 },
{ rowIndex: 135, colIndex: 3, rowspan: 2, colspan: 2 },
{ rowIndex: 140, colIndex: 9, rowspan: 3, colspan: 2 },
{ rowIndex: 145, colIndex: 16, rowspan: 2, colspan: 3 },
{ rowIndex: 150, colIndex: 23, rowspan: 4, colspan: 1 },
{ rowIndex: 155, colIndex: 2, rowspan: 2, colspan: 2 },
{ rowIndex: 160, colIndex: 5, rowspan: 3, colspan: 1 },
{ rowIndex: 165, colIndex: 11, rowspan: 2, colspan: 3 },
{ rowIndex: 170, colIndex: 19, rowspan: 4, colspan: 1 },
{ rowIndex: 175, colIndex: 26, rowspan: 2, colspan: 2 },
{ rowIndex: 180, colIndex: 1, rowspan: 3, colspan: 2 },
{ rowIndex: 185, colIndex: 8, rowspan: 2, colspan: 3 },
{ rowIndex: 190, colIndex: 13, rowspan: 4, colspan: 1 },
{ rowIndex: 195, colIndex: 20, rowspan: 2, colspan: 2 },
{ rowIndex: 200, colIndex: 28, rowspan: 3, colspan: 1 },
{ rowIndex: 205, colIndex: 4, rowspan: 2, colspan: 3 },
{ rowIndex: 210, colIndex: 10, rowspan: 4, colspan: 1 },
{ rowIndex: 215, colIndex: 17, rowspan: 2, colspan: 2 },
{ rowIndex: 220, colIndex: 25, rowspan: 3, colspan: 1 },
{ rowIndex: 225, colIndex: 0, rowspan: 2, colspan: 3 },
{ rowIndex: 230, colIndex: 6, rowspan: 4, colspan: 1 },
{ rowIndex: 235, colIndex: 12, rowspan: 2, colspan: 2 },
{ rowIndex: 240, colIndex: 22, rowspan: 3, colspan: 1 },
{ rowIndex: 245, colIndex: 24, rowspan: 2, colspan: 3 },
{ rowIndex: 250, colIndex: 3, rowspan: 4, colspan: 1 },
{ rowIndex: 255, colIndex: 9, rowspan: 2, colspan: 2 },
{ rowIndex: 260, colIndex: 15, rowspan: 3, colspan: 1 },
{ rowIndex: 265, colIndex: 18, rowspan: 2, colspan: 3 },
{ rowIndex: 270, colIndex: 27, rowspan: 4, colspan: 1 },
{ rowIndex: 275, colIndex: 2, rowspan: 2, colspan: 2 },
{ rowIndex: 280, colIndex: 7, rowspan: 3, colspan: 2 },
{ rowIndex: 285, colIndex: 14, rowspan: 2, colspan: 3 },
{ rowIndex: 290, colIndex: 21, rowspan: 4, colspan: 1 },
{ rowIndex: 295, colIndex: 1, rowspan: 2, colspan: 2 },
{ rowIndex: 300, colIndex: 5, rowspan: 3, colspan: 1 },
{ rowIndex: 305, colIndex: 11, rowspan: 2, colspan: 3 },
{ rowIndex: 310, colIndex: 19, rowspan: 4, colspan: 1 },
{ rowIndex: 315, colIndex: 26, rowspan: 2, colspan: 2 },
{ rowIndex: 320, colIndex: 4, rowspan: 3, colspan: 2 },
{ rowIndex: 325, colIndex: 8, rowspan: 2, colspan: 3 },
{ rowIndex: 330, colIndex: 13, rowspan: 4, colspan: 1 },
{ rowIndex: 335, colIndex: 20, rowspan: 2, colspan: 2 },
{ rowIndex: 340, colIndex: 28, rowspan: 3, colspan: 1 },
{ rowIndex: 345, colIndex: 0, rowspan: 2, colspan: 3 },
{ rowIndex: 350, colIndex: 6, rowspan: 4, colspan: 1 },
{ rowIndex: 355, colIndex: 12, rowspan: 2, colspan: 2 },
{ rowIndex: 360, colIndex: 16, rowspan: 3, colspan: 1 },
{ rowIndex: 365, colIndex: 23, rowspan: 2, colspan: 3 },
{ rowIndex: 370, colIndex: 25, rowspan: 4, colspan: 1 },
{ rowIndex: 375, colIndex: 3, rowspan: 2, colspan: 2 },
{ rowIndex: 380, colIndex: 10, rowspan: 3, colspan: 2 },
{ rowIndex: 385, colIndex: 17, rowspan: 2, colspan: 3 },
{ rowIndex: 390, colIndex: 22, rowspan: 4, colspan: 1 },
{ rowIndex: 395, colIndex: 2, rowspan: 2, colspan: 2 },
{ rowIndex: 400, colIndex: 15, rowspan: 3, colspan: 1 },
{ rowIndex: 410, colIndex: 18, rowspan: 2, colspan: 3 },
{ rowIndex: 420, colIndex: 24, rowspan: 4, colspan: 1 },
{ rowIndex: 430, colIndex: 7, rowspan: 2, colspan: 2 },
{ rowIndex: 440, colIndex: 21, rowspan: 3, colspan: 1 },
{ rowIndex: 450, colIndex: 27, rowspan: 2, colspan: 3 },
{ rowIndex: 460, colIndex: 4, rowspan: 4, colspan: 1 },
{ rowIndex: 470, colIndex: 9, rowspan: 2, colspan: 2 },
{ rowIndex: 480, colIndex: 14, rowspan: 3, colspan: 1 },
{ rowIndex: 490, colIndex: 20, rowspan: 2, colspan: 3 },
];
const columns: VueTableColumn[] = Array.from({ length: COL_COUNT }, (_, i) => ({
key: `extra_${i}`,
title: `列 ${i}`,
width: 200,
}));
const list = Array.from({ length: ROW_COUNT }, (_, i) => {
const row: Record<string, unknown> = { id: i };
for (let c = 0; c < COL_COUNT; c++) {
row[`extra_${c}`] = `${i}-${c}-${faker.lorem.words(6)}`;
}
return row;
});
const tableRef = ref<VirtTableVueInstance | null>(null);
const mergeOn = ref(true);
const status = ref(`表身合并:${ROW_COUNT} 行 × ${COL_COUNT} 列`);
const options = {
list,
itemKey: 'id',
estimatedSize: 40,
buffer: 4,
merges: MERGES,
border: true,
showHeader: false,
highlightSelectRow: true,
highlightSelectCol: true,
highlightSelectCell: true,
};
const scrollTop = () => {
tableRef.value?.scrollToTop();
status.value = '已滚动到顶部';
};
const scrollBottom = () => {
tableRef.value?.scrollToBottom();
status.value = '已滚动到底部';
};
const scrollRandom = () => {
const index = Math.floor(Math.random() * ROW_COUNT);
tableRef.value?.scrollToIndex(index);
status.value = `随机滚动到第 ${index + 1} 行`;
};
const scrollTo500 = () => {
tableRef.value?.scrollToIndex(499);
status.value = '已滚动到第 500 行';
};
const toggleMerge = () => {
mergeOn.value = !mergeOn.value;
tableRef.value?.setMerges(mergeOn.value ? MERGES : []);
status.value = mergeOn.value ? '合并单元格已启用' : '合并单元格已关闭';
};
</script>