加载第三方单元格组件
以element-plus为例
源码
vue
<template>
<div class="base-view">
<div style="width: 100%; height: 600px; border: 2px solid var(--el-color-border)">
<Grid
:columns="columns"
:list="list"
:options="{
border: true,
textOverflow: 'ellipsis',
minRowHeight: minRowHeight,
}"
></Grid>
</div>
</div>
</template>
<script setup lang="tsx">
import { ref } from 'vue';
import { Grid, type Column, type ListItem } from 'vue-virt-grid';
import {
SelectCover,
SelectDropdown,
SelectView,
DateView,
DateCover,
DateDropdown,
LinkView,
PersonView,
CellType,
type TdData,
// closeDropdown,
} from 'vue-virt-grid';
import {
ElInput,
ElButton,
ElSelect,
ElOption,
ElDatePicker,
ElTimePicker,
ElCascader,
} from 'element-plus';
import 'element-plus/dist/index.css';
// const generateColumns = (length = 10, prefix = 'field-', props?: any) =>
// Array.from({ length }).map((_, columnIndex) => ({
// ...props,
// field: `${prefix}${columnIndex}`,
// title: `Title ${columnIndex}`,
// width: 200,
// }));
const minRowHeight = 32;
const generateList = (columns: Column[], length = 10000, prefix = 'row-') =>
Array.from({ length }).map((_, rowIndex) => {
return columns.reduce(
(rowData, column, columnIndex) => {
if (column.field === 'select') {
rowData[column.field] = 'key1';
} else if (column.field === 'cascader') {
rowData[column.field] = 'feedback';
} else if (column.field === 'date') {
rowData[column.field] = '2020-01-01';
} else if (column.field === 'time') {
rowData[column.field] = '18:20:52';
} else {
rowData[column.field] = `Row ${rowIndex} - Field ${columnIndex}`;
}
return rowData;
},
{
id: `${prefix}${rowIndex}`,
parentId: null,
},
);
});
const selectOptions = [
{ value: 'key1', label: '选项1', bg: '#ffe8e6' },
{ value: 'key2', label: '选项2', bg: '#e6f7ff' },
{ value: 'key3', label: '选项3', bg: 'rgb(2, 179, 161)' },
{ value: 'key4', label: '选项4', bg: 'rgb(2, 179, 161)' },
{ value: 'key5', label: '选项5', bg: 'rgb(2, 179, 161)' },
{ value: 'key6', label: '选项6', bg: 'rgb(2, 179, 161)' },
{ value: 'key7', label: '选项7', bg: 'rgb(2, 179, 161)' },
{ value: 'key8', label: '选项8', bg: 'rgb(2, 179, 161)' },
{ value: 'key9', label: '选项9', bg: 'rgb(2, 179, 161)' },
{ value: 'key10', label: '选项10', bg: 'rgb(2, 179, 161)' },
{ value: 'key11', label: '选项11', bg: 'rgb(2, 179, 161)' },
{ value: 'key12', label: '选项12', bg: 'rgb(2, 179, 161)' },
{ value: 'key13', label: '选项13', bg: 'rgb(2, 179, 161)' },
];
const cascaderOptions = [
{
value: 'guide',
label: 'Guide',
children: [
{
value: 'disciplines',
label: 'Disciplines',
children: [
{
value: 'consistency',
label: 'Consistency',
},
{
value: 'feedback',
label: 'Feedback',
},
{
value: 'efficiency',
label: 'Efficiency',
},
{
value: 'controllability',
label: 'Controllability',
},
],
},
{
value: 'navigation',
label: 'Navigation',
children: [
{
value: 'side nav',
label: 'Side Navigation',
},
{
value: 'top nav',
label: 'Top Navigation',
},
],
},
],
},
];
function findLabelByValue(value: string, options: any[]): string | null {
for (const option of options) {
if (option.value === value) {
return option.label;
}
if (option.children) {
const label = findLabelByValue(value, option.children);
if (label) return label;
}
}
return null;
}
const columns: Column[] = [
{
field: 'input',
title: 'ElInput',
width: 200,
cellCoverRender: ({ column, row }: TdData) => (
<ElInput
v-model={row[column.field]}
style="width: 100%; height: 36px;"
placeholder="Please input"
/>
),
},
{
field: 'select',
title: 'ElSelect',
width: 200,
cellRender: ({ column, row }: TdData) => (
<div class="vtg-cell">
{selectOptions.find((item) => item.value === row[column.field])?.label ?? '请选择'}
</div>
),
cellCoverRender: ({ column, row }: TdData) => (
<ElSelect v-model={row[column.field]} style="width: 100%; height: 36px;" placeholder="Select">
{selectOptions.map((item) => (
<ElOption label={item.label} value={item.value} />
))}
</ElSelect>
),
},
{
field: 'cascader',
title: 'ElCascader',
width: 200,
cellRender: ({ column, row }: TdData) => (
<div class="vtg-cell">{findLabelByValue(row[column.field], cascaderOptions)}</div>
),
cellCoverRender: ({ column, row }: TdData) => (
<ElCascader
v-model={row[column.field]}
style="width: 100%; height: 36px;"
showAllLevels={false}
options={cascaderOptions}
/>
),
},
{
field: 'date',
title: 'ElDatePicker',
width: 200,
cellRender: ({ column, row }: TdData) => (
<div class="vtg-cell">
<div style="width: 14px; height: 14px; margin-right: 8px">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
<path
fill="currentColor"
d="M128 384v512h768V192H768v32a32 32 0 1 1-64 0v-32H320v32a32 32 0 0 1-64 0v-32H128v128h768v64zm192-256h384V96a32 32 0 1 1 64 0v32h160a32 32 0 0 1 32 32v768a32 32 0 0 1-32 32H96a32 32 0 0 1-32-32V160a32 32 0 0 1 32-32h160V96a32 32 0 0 1 64 0zm-32 384h64a32 32 0 0 1 0 64h-64a32 32 0 0 1 0-64m0 192h64a32 32 0 1 1 0 64h-64a32 32 0 1 1 0-64m192-192h64a32 32 0 0 1 0 64h-64a32 32 0 0 1 0-64m0 192h64a32 32 0 1 1 0 64h-64a32 32 0 1 1 0-64m192-192h64a32 32 0 1 1 0 64h-64a32 32 0 1 1 0-64m0 192h64a32 32 0 1 1 0 64h-64a32 32 0 1 1 0-64"
></path>
</svg>
</div>
<div>{row[column.field]}</div>
</div>
),
cellCoverRender: ({ column, row }: TdData) => (
<ElDatePicker
v-model={row[column.field]}
value-format="YYYY-MM-DD"
style="width: 100%; height: 36px;"
placeholder="Pick a day"
type="date"
></ElDatePicker>
),
},
{
field: 'time',
title: 'ElTimePicker',
width: 200,
cellRender: ({ column, row }: TdData) => (
<div class="vtg-cell">
<div style="width: 14px; height: 14px; margin-right: 8px">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
<path
fill="currentColor"
d="M512 896a384 384 0 1 0 0-768 384 384 0 0 0 0 768m0 64a448 448 0 1 1 0-896 448 448 0 0 1 0 896"
></path>
<path
fill="currentColor"
d="M480 256a32 32 0 0 1 32 32v256a32 32 0 0 1-64 0V288a32 32 0 0 1 32-32"
></path>
<path
fill="currentColor"
d="M480 512h256q32 0 32 32t-32 32H480q-32 0-32-32t32-32"
></path>
</svg>
</div>
<div>{row[column.field]}</div>
</div>
),
cellCoverRender: ({ column, row }: TdData) => {
return (
<ElTimePicker
v-model={row[column.field]}
value-format="HH:mm:ss"
style="width: 100%; height: 36px;"
placeholder="Arbitrary time"
type="date"
></ElTimePicker>
);
},
},
{
field: 'button',
title: 'ElButton',
width: 200,
cellRender: () => <ElButton type="primary">Primary</ElButton>,
},
];
const list: any = ref(generateList(columns, 200));
</script>
<style lang="scss">
.base-view {
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
</style>