Skip to content
On this page

可编辑表格

编辑行

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>

手动控制编辑行

可通过设置 editByClickRowfalse 来禁用点击行编辑功能, 然后通过 editableRowKeyeditRow 等方法来手动控制编辑行.

以下示例中, 通过 editedRowKey 设置默认编辑 id1 的行. 另可通过操作列的按钮来控制编辑行.

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 组件提供了 bodyEditableCellbodyEditableCellControl 两个 slot 来自定义编辑状态下的单元格和单元格控件.

bodyEditableCell vs bodyEditableCellControl:

  • bodyEditableCell 的优先级高于 bodyEditableCellControl.
  • bodyEditableCell 用于自定义编辑状态下的单元格, 可以通过 slot 传出的 validateInfos 来获取校验信息.
  • bodyEditableCellControl 用于自定义编辑状态下的单元格中的输入控件, 会保留表单校验功能.
slot 参数
参数说明类型
......-
field编辑状态下该单元格对应的表单项配置-
validateInfos编辑状态下该单元格中表单项的校验信息-
popupContainereditByClickRow 为 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>