Ant Design Vue 表格行内编辑!!!

效果图

无图言叼,直接上图:
在这里插入图片描述
在这里插入图片描述

应用场景

对于修改表格数据,比较主流的是通过模态框内嵌表单来修改。这样上手比较简单,验证功能很强大。如果通过表格行内编辑的话,上手稍微复杂一点,直接在列里面修改,会非常直观顺畅,但是有一定的缺陷,无法内嵌表单,验证起来比较不友好。

.Vue

<template>
  <div>
    <div class="page-location-wrapper">
      <bread-nav :nav-list="['数据模版', '数据模版DEMO']"/>
      <h1>数据模版DEMO</h1>
    </div>
    <div class="public-container">
      <div class="public-operation-bar">
        <div class="button-wrapper">
          <a-button icon="plus-circle" type="primary"
                    @click="addRow">新增
          </a-button>
          <a-button type="primary">批量发布</a-button>
        </div>
      </div>
      <a-divider/>
      <div class="table-wrapper">
        <!--每个列的宽度必须比列名总长度大才能使表格所有列对齐,留一个列不设置宽度-->
        <a-table
          :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange, onSelectAll: onSelectAllChange}"
          :columns="columns"
          :dataSource="tableData"
          bordered
          size="middle"
          :pagination="pagination"
          :loading="tableLoading"
          :scroll="{x: 2050}"
        >
          <template
            v-for="col in customRenderList"
            v-slot:[col]="text, record, index"
          >
            <div :key="col">
              <a-input
                :read-only="readonlyArr.includes(col)"
                placeholder="请输入"
                v-if="record.editable && inputScopedSlots.includes(col)"
                :value="text"
                @change="e => handleChange(e.target.value, record.key, col)"
              />
              <a-date-picker
                placeholder="请选择时间"
                v-else-if="record.editable && dateScopedSlots.includes(col)"
                :value="momentDateStr(text)"
                @change="onChangeDate($event, record.key, col)"
              />
              <a-select
                placeholder="请选择"
                style="display: block;"
                v-else-if="record.editable && selectScopedSlots.includes(col)"
                :value="text"
                @change="onChangeSelect($event, record.key, col)"
              >
                <a-select-option value="lucy">Lucy</a-select-option>
                <a-select-option value="jack">Jack</a-select-option>
              </a-select>
              <span v-else>{{text}}</span>
            </div>
          </template>

          <template #action="text, record, index">
            <div class="editable-row-operations">
              <div v-if="record.editable">
                <a @click="save(record.key)">保存</a>
                <a-divider type="vertical"/>
                <a @click="cancel(record.key)">取消</a>
              </div>
              <div v-else>
                <a @click="edit(record.key)">编辑</a>
              </div>
            </div>
          </template>
        </a-table>
      </div>
    </div>
  </div>
</template>

<script>
  import Mixin from './mixin'
  import Moment from 'moment'

  export default {
    name: "DataTemplateDemo",
    mixins: [Mixin],
    methods: {
      // 将时间字符串 转换 为 Moment
      momentDateStr(dateStr) {
        return Moment(dateStr)
      }
    }
  }
</script>

Mixin

import {clearReference} from '@/utils/utils'

const data = []

for (let i = 0; i < 10; i++) {
  data.push({
    key: i,
    a: '2019-12-17',
    b: 'lucy',
    c: '22',
    e: '22',
    d: '22',
    f: '22',
    g: '22',
    h: '22',
    i: '22',
    j: '22',
    editable: false
  })
}

const Mixin = {
  data() {
    return {
      // 表格列 - 为了方便使 dataIndex === scopedSlots.customRender
      columns: [
        {title: '左边固定', width: 200, align: 'center', dataIndex: 'a', fixed: 'left', scopedSlots: {customRender: 'a'}},
        {title: '测试列3', width: 200, dataIndex: 'b', scopedSlots: {customRender: 'b'}},
        {title: '测试列4', width: 200, dataIndex: 'c', scopedSlots: {customRender: 'c'}},
        {
          title: '测试列5', width: 200, children: [
            {title: '分组1', width: 200, dataIndex: 'e', scopedSlots: {customRender: 'e'}},
            {title: '分组2', width: 200, dataIndex: 'j', scopedSlots: {customRender: 'j'}},
          ]
        },
        {title: '测试列6', width: 200, dataIndex: 'f', scopedSlots: {customRender: 'f'}},
        {title: '测试列7', width: 200, dataIndex: 'g', scopedSlots: {customRender: 'g'}},
        {title: '测试列8', width: 200, dataIndex: 'h', scopedSlots: {customRender: 'h'}},
        {title: '测试列8', dataIndex: 'i', scopedSlots: {customRender: 'i'}},
        {title: '右边固定2', width: 200, align: 'center', scopedSlots: {customRender: 'action'}, fixed: 'right'},
      ],
      // 表格数据
      tableData: [],
      // 表格缓存的数据 - 用来点击取消时回显数据
      cacheData: [],
      // 每一列的插槽名 - 表格行内编辑用
      customRenderList: ['a', 'b', 'c', 'e', 'f', 'g', 'h', 'i', 'j'],
      // 用来匹配插槽中显示input框
      inputScopedSlots: ['c', 'e', 'f', 'g', 'h', 'i', 'j'],
      // 用来匹配插槽中显示date框
      dateScopedSlots: ['a'],
      // 用来匹配插槽中显示select框
      selectScopedSlots: ['b'],
      // 对于某些自动赋值的input框设为 只读
      readonlyArr: ['c'],
      // 表格分页
      pagination: {
        current: 1,
        size: 'large',
        pageSize: 10, // 默认每页显示数量
        total: 0, // 总条数
        showQuickJumper: true,
        showTotal: (total, range) => `总共 ${total} 条记录,当前第 ${range[0]}条至第${range[1]}条`,
        onChange: (page) => this.pageChange(page)
      },
      // 表格loading
      tableLoading: false,
      // 表格选中key
      selectedRowKeys: []
    }
  },
  created() {
    // 此处模拟ajax,赋值(需清除引用)
    this.tableData = clearReference(data)
    this.cacheData = clearReference(data)
  },
  methods: {
    // 分页事件
    pageChange(page) {
      this.pagination.current = page
    },
    // 表格选中事件
    onSelectChange(selectedRowKeys) {
      console.log(selectedRowKeys);
      this.selectedRowKeys = selectedRowKeys;
    },
    // 表格点击全选事件
    onSelectAllChange(selected, selectedRows) {
      // 判断 全选并且第一行数据为新增 则不选中新增那一行
      if (selected && selectedRows[0].key === 'newRow') {
        this.selectedRowKeys.splice(0, 1)
      }
    },
    // 添加一行
    addRow() {
      if (this.tableData.some(item => item.newRow === true)) return this.$message.info('请先编辑完毕后在再添加!');

      // 新增时取消表格选中的key
      this.selectedRowKeys = []

      this.tableData.unshift({
        key: 'newRow',  // newRow 表示该行是新增的,提交成功后 key替换为数据库ID
        newRow: true,   //用来限制只能新增一行
        a: this.$dateformat(new Date(), 'isoDate'),
        b: undefined,
        c: '',
        e: '',
        d: '',
        f: '',
        g: '',
        h: '',
        i: '',
        j: '',
        editable: true
      })
      this.cacheData.unshift({
        key: 'newRow',
        newRow: true,
        a: this.$dateformat(new Date(), 'isoDate'),
        b: undefined,
        c: '',
        e: '',
        d: '',
        f: '',
        g: '',
        h: '',
        i: '',
        j: '',
        editable: false
      })
    },
    // 编辑一行
    edit(rowKey) {
      const newData = [...this.tableData];
      const target = newData.filter(item => rowKey === item.key)[0];
      // 根据rowKey判断该行数据是否存在
      if (target) {
        target.editable = true;   // 修改target可以直接影响到newData
        this.tableData = newData;
      }
    },
    // 点击保存
    save(rowKey) {
      const newData = [...this.tableData];
      const target = newData.filter(item => rowKey === item.key)[0];
      if (target) {
        delete target.editable;
        this.tableData = newData;
        this.cacheData = newData.map(item => ({...item}));
      }
    },
    // 点击取消
    cancel(rowKey) {
      const newData = [...this.tableData];
      const target = newData.filter(item => rowKey === item.key)[0];
      if (target) {
        // 将缓存数据中匹配到的数据对象覆盖合并当前被修改的行
        Object.assign(target, this.cacheData.filter(item => rowKey === item.key)[0]);
        delete target.editable;
        this.tableData = newData;
      }
    },
    // input 输入change
    handleChange(value, rowKey, colName) {
      const newData = [...this.tableData];
      const target = newData.filter(item => rowKey === item.key)[0];
      if (target) {
        target[colName] = value;
        this.tableData = newData;
      }
    },
    // 日期框 change
    onChangeDate($event, rowKey, colName) {
      const newData = [...this.tableData];
      const target = newData.filter(item => rowKey === item.key)[0];
      if (target) {
        target[colName] = this.$dateformat($event, 'isoDate');
        this.tableData = newData;
      }
    },
    // select 框 change
    onChangeSelect($event, rowKey, colName) {
      const newData = [...this.tableData];
      const target = newData.filter(item => rowKey === item.key)[0];
      if (target) {
        target[colName] = $event;

        // 根据select框的值自动带出某个input的值 - 因为第三列列名为c
        $event === 'lucy' ? target.c = '根据lucy带出的值' : target.c = '根据jack带出的值'

        this.tableData = newData;
      }
    }
  }
}

export default Mixin

实现原理

基于antV官方的一个 demo 加上自己一些新增的实现,具体实现在代码里面有非常详细的注释。无奈没有更多的时间去优化这篇长大粗的博文,目前只能简单粗暴的将demo代码粘上来。

补充

对于文中的 clearReference 方法其实就是 JSON.parse(JSON.stringify(obj))
补充于 2021年3月22日:this.$dateformat 是 https://www.npmjs.com/package/dateformat 插件

  • 13
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论
对于Ant Design Vue中的表格编辑,你可以使用Table组件的editable属性来实现。首先,设置editable为true,然后在columns中定义需要编辑的列,并指定相应的编辑器组件。 以下是一个示例代码,展示如何在Ant Design Vue中实现表格编辑: ```vue <template> <a-table :columns="columns" :data-source="data" :row-key="record => record.id"> <template slot="name" slot-scope="{ record, index }"> <a-input v-model="record.name" :disabled="!record.editable" /> </template> <template slot="email" slot-scope="{ record, index }"> <a-input v-model="record.email" :disabled="!record.editable" /> </template> <template slot="operation" slot-scope="{ record, index }"> <a-button @click="handleEdit(record)">编辑</a-button> <a-button @click="handleSave(record)">保存</a-button> <a-button @click="handleCancel(record)">取消</a-button> </template> </a-table> </template> <script> export default { data() { return { data: [ { id: 1, name: 'John', email: 'john@example.com', editable: false }, { id: 2, name: 'Jane', email: 'jane@example.com', editable: false }, ], columns: [ { title: '姓名', dataIndex: 'name' }, { title: '邮箱', dataIndex: 'email' }, { title: '操作', dataIndex: 'operation' }, ], }; }, methods: { handleEdit(record) { record.editable = true; }, handleSave(record) { record.editable = false; // 在这里可以进行保存操作,例如向后端提交数据 }, handleCancel(record) { record.editable = false; // 在这里可以进行取消操作,例如恢复原始数据 }, }, }; </script> ``` 上述代码中,我们使用了Ant Design VueTable组件,通过设置editable属性为true来启用行编辑功能。每个需要编辑的列都使用了具名插槽,并使用a-input组件作为编辑器。 在表格中,我们还添加了三个操作按钮:编辑、保存和取消。点击编辑按钮会将对应行的editable属性设置为true,使该行变为可编辑状态。点击保存按钮会将对应行的editable属性设置为false,并可以在handleSave方法中进行保存数据的操作。点击取消按钮会将对应行的editable属性设置为false,并可以在handleCancel方法中进行取消编辑的操作。 希望以上示例能帮助到你实现Ant Design Vue表格编辑功能。
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帝尊菜鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值