可编辑表格
编辑行
javascript
import { computed, ref, watch } from "vue";
import dayjs from "dayjs";
import { FormItemControlType } from "@nbicc/common-components";
import { requestPosts, requestPost } from "../../mock";
const dataSource = ref([]);
const total = computed(() => dataSource.value.length);
const editedRowKey = ref();
watch(editedRowKey, () => console.log(editedRowKey.value));
const columns = [
{ title: "Id", dataIndex: "id", fixed: "left", ellipsis: true },
{ title: "Name", dataIndex: "name", sorter: true, ellipsis: true },
{ title: "Description", dataIndex: "description", ellipsis: true },
{ title: "Level", dataIndex: "level", ellipsis: true },
{ title: "Updated At", dataIndex: "updatedAt", ellipsis: true }
];
const fields = ref([
{ name: "name", label: "Name", type: FormItemControlType.INPUT, rules: [{ required: true }] },
{ name: "level", label: "Level", type: FormItemControlType.INPUT_NUMBER },
[
{
name: "description",
label: "Description",
type: FormItemControlType.TEXT_AREA
},
{
autoSize: { minRows: 2, maxRows: 6 },
maxlength: 100,
showCount: true
}
],
{ name: "updatedAt", label: "Updated At", type: FormItemControlType.DATE_PICKER }
]);
const editableTableRef = ref();
async function requestDataSource() {
const data = await requestPosts(1, 10);
data.data.forEach((item) => {
item.createdAt = dayjs(item.createdAt);
item.updatedAt = dayjs(item.updatedAt);
});
dataSource.value = data.data;
}
requestDataSource();
function handleAdd() {
const record = requestPost();
record.createdAt = dayjs(record.createdAt);
record.updatedAt = dayjs(record.updatedAt);
dataSource.value.push({
id: dataSource.value[dataSource.value.length - 1].id + 1,
...record
});
}html
<template>
<div>
<n-button @click="handleAdd">Add</n-button>
</div>
<n-table
ref="editableTableRef"
size="small"
row-key="id"
v-model:edited-row-key="editedRowKey"
:data-source="dataSource"
:total="total"
:columns="columns"
:fields="fields"
:pagination="false"
editable
>
<template #bodyCell="{ record, column }">
<template v-if="column.dataIndex === 'updatedAt'">
{{ record.updatedAt?.format("YYYY-MM-DD HH:mm:ss") }}
</template>
</template>
</n-table>
</template>手动控制编辑行
可通过设置 editByClickRow 为 false 来禁用点击行编辑功能, 然后通过 editableRowKey 和 editRow 等方法来手动控制编辑行.
以下示例中, 通过 editedRowKey 设置默认编辑 id 为 1 的行. 另可通过操作列的按钮来控制编辑行.
javascript
import { computed, ref, watch } from "vue";
import dayjs from "dayjs";
import { FormItemControlType } from "@nbicc/common-components";
import { requestPosts, requestPost } from "../../mock";
const dataSource = ref([]);
const total = computed(() => dataSource.value.length);
const editedRowKey = ref(1);
watch(editedRowKey, () => console.log(editedRowKey.value));
const columns = [
{ title: "Id", dataIndex: "id", fixed: "left", ellipsis: true },
{ title: "Name", dataIndex: "name", sorter: true, ellipsis: true },
{ title: "Level", dataIndex: "level", ellipsis: true },
{ title: "Updated At", dataIndex: "updatedAt", ellipsis: true },
{ title: "Operator", dataIndex: "operator", width: 256 }
];
const fields = ref([
{ name: "name", label: "Name", type: FormItemControlType.INPUT, rules: [{ required: true }] },
{ name: "level", label: "Level", type: FormItemControlType.INPUT_NUMBER },
{ name: "updatedAt", label: "Updated At", type: FormItemControlType.DATE_PICKER }
]);
const editableTableRef = ref();
async function requestDataSource() {
const data = await requestPosts(1, 5);
data.data.forEach((item) => {
item.createdAt = dayjs(item.createdAt);
item.updatedAt = dayjs(item.updatedAt);
});
dataSource.value = data.data;
}
requestDataSource();
function handleAdd() {
const record = requestPost();
record.createdAt = dayjs(record.createdAt);
record.updatedAt = dayjs(record.updatedAt);
dataSource.value.push({
id: dataSource.value[dataSource.value.length - 1].id + 1,
...record
});
}html
<template>
<div>
<n-button @click="handleAdd">Add</n-button>
</div>
<n-table
ref="editableTableRef"
size="small"
row-key="id"
v-model:edited-row-key="editedRowKey"
:data-source="dataSource"
:total="total"
:columns="columns"
:fields="fields"
:pagination="false"
:edit-by-click-row="false"
editable
>
<template #bodyCell="{ record, column }">
<template v-if="column.dataIndex === 'operator'">
<a-space :size="0">
<n-button type="link" size="small" @click="editableTableRef.editRow(record.id)"
>编辑</n-button
>
<n-button type="link" size="small" @click="editableTableRef.saveEditedRow()"
>校验并保存</n-button
>
<n-button type="link" size="small" @click="editableTableRef.saveEditedRow(false)"
>直接保存</n-button
>
<n-button type="link" size="small" danger @click="editableTableRef.cancelEditedRow()"
>取消</n-button
>
</a-space>
</template>
<template v-if="column.dataIndex === 'updatedAt'">
{{ record.updatedAt?.format("YYYY-MM-DD HH:mm:ss") }}
</template>
</template>
</n-table>
</template>添加校验规则
校验规则可以通过 fields 属性来配置, 与 NForm 的 fields 属性一致.
javascript
import { computed, ref, watch } from "vue";
import dayjs from "dayjs";
import { FormItemControlType } from "@nbicc/common-components";
import { requestPosts } from "../../mock";
const dataSource = ref([]);
const total = computed(() => dataSource.value.length);
const editedRowKey = ref();
watch(editedRowKey, () => console.log(editedRowKey.value));
const columns = [
{ title: "Id", dataIndex: "id", fixed: "left", ellipsis: true },
{ title: "Name", dataIndex: "name", sorter: true, ellipsis: true },
{ title: "Description", dataIndex: "description", ellipsis: true },
{ title: "Level", dataIndex: "level", ellipsis: true },
{ title: "Updated At", dataIndex: "updatedAt", ellipsis: true },
{ title: "Operator", dataIndex: "operator", fixed: "right", width: 256 }
];
const fields = ref([
{ name: "name", label: "Name", type: FormItemControlType.INPUT, rules: [{ required: true }] },
{
name: "level",
label: "Level",
type: FormItemControlType.INPUT_NUMBER,
rules: [
{
validator: async (_, value) => {
if (value < 233) throw new Error("level 不可小于 233");
}
}
]
},
[
{
name: "description",
label: "Description",
type: FormItemControlType.TEXT_AREA
},
{
autoSize: { minRows: 2, maxRows: 6 },
maxlength: 100,
showCount: true
}
],
{ name: "updatedAt", label: "Updated At", type: FormItemControlType.DATE_PICKER }
]);
const editableTableRef = ref();
async function requestDataSource() {
const data = await requestPosts(1, 10);
data.data.forEach((item) => {
item.createdAt = dayjs(item.createdAt);
item.updatedAt = dayjs(item.updatedAt);
});
dataSource.value = data.data;
}
requestDataSource();html
<template>
<n-table
ref="editableTableRef"
size="small"
row-key="id"
v-model:edited-row-key="editedRowKey"
:data-source="dataSource"
:total="total"
:columns="columns"
:fields="fields"
:pagination="false"
:edit-by-click-row="false"
editable
:scroll="{ x: 800 }"
>
<template #bodyCell="{ record, column }">
<template v-if="column.dataIndex === 'operator'">
<a-space :size="0">
<n-button type="link" size="small" @click="editableTableRef.editRow(record.id)"
>编辑</n-button
>
<n-button type="link" size="small" @click="editableTableRef.saveEditedRow()"
>校验并保存</n-button
>
<n-button type="link" size="small" @click="editableTableRef.saveEditedRow(false)"
>直接保存</n-button
>
<n-button type="link" size="small" danger @click="editableTableRef.cancelEditedRow()"
>取消</n-button
>
</a-space>
</template>
<template v-if="column.dataIndex === 'updatedAt'">
{{ record.updatedAt?.format("YYYY-MM-DD HH:mm:ss") }}
</template>
</template>
</n-table>
</template>使用 slot 自定义控件
NTable 组件提供了 bodyEditableCell 和 bodyEditableCellControl 两个 slot 来自定义编辑状态下的单元格和单元格控件.
bodyEditableCell vs bodyEditableCellControl:
bodyEditableCell的优先级高于bodyEditableCellControl.bodyEditableCell用于自定义编辑状态下的单元格, 可以通过 slot 传出的validateInfos来获取校验信息.bodyEditableCellControl用于自定义编辑状态下的单元格中的输入控件, 会保留表单校验功能.
slot 参数
| 参数 | 说明 | 类型 |
|---|---|---|
| ... | ... | - |
| field | 编辑状态下该单元格对应的表单项配置 | - |
| validateInfos | 编辑状态下该单元格中表单项的校验信息 | - |
| popupContainer | editByClickRow 为 ture 时, 如果自定义元素有弹出框(如: Select, TimePicker)请将弹出层容器设置为该值 | HTMLElement |
以下示例中, Name 列使用了 bodyEditableCellControl 来自定义输入控件, 并保留了校验功能. Level 列使用了 bodyEditableCell 来自定义单元格, 并通过 validateInfos 来获取校验信息.
javascript
import { computed, ref, watch } from "vue";
import dayjs from "dayjs";
import { FormItemControlType } from "@nbicc/common-components";
import { requestPosts } from "../../mock";
const dataSource = ref([]);
const total = computed(() => dataSource.value.length);
const editedRowKey = ref();
watch(editedRowKey, () => console.log(editedRowKey.value));
const columns = [
{ title: "Id", dataIndex: "id", fixed: "left", ellipsis: true },
{ title: "Name", dataIndex: "name", sorter: true, ellipsis: true },
{ title: "Level", dataIndex: "level", ellipsis: true },
{ title: "Updated At", dataIndex: "updatedAt", ellipsis: true },
{ title: "Operator", dataIndex: "operator", width: 256 }
];
const fields = ref([
{ name: "name", label: "Name", type: FormItemControlType.INPUT, rules: [{ required: true }] },
{
name: "level",
label: "Level",
type: FormItemControlType.INPUT_NUMBER,
rules: [{ required: true }]
},
{ name: "updatedAt", label: "Updated At", type: FormItemControlType.DATE_PICKER }
]);
const editableTableRef = ref();
async function requestDataSource() {
const data = await requestPosts(1, 5);
data.data.forEach((item) => {
item.createdAt = dayjs(item.createdAt);
item.updatedAt = dayjs(item.updatedAt);
});
dataSource.value = data.data;
}
requestDataSource();html
<template>
<n-table
ref="editableTableRef"
size="small"
row-key="id"
v-model:edited-row-key="editedRowKey"
:data-source="dataSource"
:total="total"
:columns="columns"
:fields="fields"
:pagination="false"
:edit-by-click-row="false"
editable
>
<template #bodyEditableCellControl="{ record, column }">
<template v-if="column.dataIndex === 'name'">
<a-input v-model:value="record.name" />
</template>
</template>
<template #bodyEditableCell="{ record, column, validateInfos }">
<template v-if="column.dataIndex === 'level'">
<a-form-item v-bind="validateInfos['level']">
<a-input v-model:value="record.level" />
</a-form-item>
</template>
</template>
<template #bodyCell="{ record, column }">
<template v-if="column.dataIndex === 'operator'">
<a-space :size="0">
<n-button type="link" size="small" @click="editableTableRef.editRow(record.id)"
>编辑</n-button
>
<n-button type="link" size="small" @click="editableTableRef.saveEditedRow()"
>校验并保存</n-button
>
<n-button type="link" size="small" @click="editableTableRef.saveEditedRow(false)"
>直接保存</n-button
>
<n-button type="link" size="small" danger @click="editableTableRef.cancelEditedRow()"
>取消</n-button
>
</a-space>
</template>
<template v-if="column.dataIndex === 'updatedAt'">
{{ record.updatedAt?.format("YYYY-MM-DD HH:mm:ss") }}
</template>
</template>
</n-table>
</template>