逐行解析Antd Design可编辑单元格

解析Antd Design可编辑单元格

背景:

在项目中肯定不免需要类似这样的表格,在单元格里面进行编辑。类似这样:
在这里插入图片描述
在这里插入图片描述

逻辑:

这是一个可编辑表格,那么就需要确定的是每次点击编辑定位到需要被编辑的那一行。就比如说我点击了第一行,那么就只能是第一行可以被编辑,其余几行都处于禁用状态。

关键代码:

我用的是antd design组件库,详情可以去官网:https://ant.design/components/table-cn/#components-table-demo-edit-cell

columns是表格列的配置。有些关键参数我在这边做些说明:

align设置列的对齐方式
dataIndex列数据在数据项中对应的路径,支持通过数组查询嵌套路径
editable是否可编辑
render生成复杂数据的渲染函数,参数分别为当前行的值,当前行数据,行索引,@return 里面可以设置表格行/列合并
title列头显示文字(函数用法 3.10.0 后支持)
width列宽度

editingKey就相当于是一个标识,当editingKey''时,就无法编辑,当其有值时就可以编辑。

isEditing函数就是把需要编辑的那一行值的key赋``editingKey值并且返回。在columns`中就根据这个返回的值来判断是否需要编辑。

const [editingKey, setEditingKey] = useState('');   
const isEditing =(record) => {
        return record.key === editingKey
    };
const columns = [
        {
            title: '操作',
            dataIndex: 'operation',
            align: 'center',
            width: '140px',
            render: (_, record) => {
                const editable = isEditing(record);
                return editable ? (
                    <span>
                        <a
                            style={{marginRight: 8}}
                            onClick={() => {
                                save(record.key)
                            }}
                        >
                            保存
                        </a>
                        <a
                            style={{marginRight: 8}}
                            onClick={() => {
                                cancel();
                            }}
                        >
                            取消
                        </a>
                    </span>
                )
                : (
                    <a
                    disabled = {editingKey !== ''}
                    onClick = {() => {
                        edit(record)
                    }}
                    >编辑</a>
                )
            }
        },
        {
            title: '供应商名称',
            dataIndex: 'accountName',
            width: '150px',
            editable: true,
        },
        {
            title: '供应商代码',
            dataIndex: 'supplierCode',
            width: '150px',
            editable: true,
        },
        {
            title: '开户行',
            dataIndex: 'bankName',
            width: '250px',
            editable: true,
        },
        {
            title: '账号',
            dataIndex: 'accountNumber',
            width: '250px',
            editable: true,
        },
    ];

点击编辑时触发该函数,把单元格里面的数据赋值到编辑框里面。说的直白一点就是当点击编辑框的时候,会出现新的输入组件,但是这个Input组件没有值,如果我们只是修改某个字的话又要重新输入一遍,所以需要把原来单元格的值赋值给输入框。

//编辑    
const edit =(record) => {
    form.setFieldsValue({
        ...record
    });
    setEditingKey(record.key)
};

取消的思想就是把editingKey赋值为'',随后recoed.key值也为'',就取消了编辑状态了。

//取消
const cancel =() => {
    setEditingKey('');
};

我在这边把编辑的组件单独封装了起来,因为可能不止一个页面需要调用该组件。

先引入该组件,具体的路径因人而异。

import EditableTable from './editableTable';

image-20211215132645950

具体使用如上图所示,源码如下:

有几个属性有必要说明一下,columns就是上文定义的表格列,scroll定义的是表格滚动区域的宽和高,data就是表格里面的数据了,这是从后端拿到的,settableselectedvalue是表格多选时选中的数据,loading是显示页面是否加载中的一个小动画。

<Form form={form} >
    <EditableTable
        columns={columns}
        scroll={{ x: 500, y: 500 }}
        style={{ width: '90%' }}
        data={data}
        isEditing={isEditing}
        setSelectedData={settableselectedvalue}
        loading={props.loading}
        />
 </Form>

现在来看被封装的EditableTable里面的代码:相关的注释已经写在了代码块里

import React, { useState } from 'react';
import { Table, Input, InputNumber, Select, Form } from 'antd';

// 这里是编辑
function EditableTable(props) {
  const { Option } = Select;
  const { TextArea } = Input;
  const EditableCell = ({
    editing,
    dataIndex,
    title,
    inputType,
    record,
    index,
    requiring,
    selectOptions,
    children,
    ...restProps
  }) => {
    return (
      // <td> 是table data cell 是用于定义表格中的单元格,必须嵌套在<tr>标签中
      <td {...restProps}>
        {/* 编辑栏中先是判断是否编辑,如果editing等于某个值,即为真,如果为真,就执行<Form.Item>里面的内容。如果为假,就执行children,继承子节点上的内容
                在Form里面又有一个是selectOptions的三目运算法, */}
        {editing ? (
          <Form.Item
            name={dataIndex}
            style={{
              margin: 0,
            }}
            rules={[
              {
                required: requiring,
                message: `请输入 ${title}!`,
              },
            ]}
          >
            {selectOptions ? selectOptions : <TextArea />}
          </Form.Item>
        ) : (
          children
        )}
      </td>
    );
  };

  // 合并col
  // 把传进来的columns依次遍历,如果columns里面的editable不为true,就原封不动的返回
  const mergedColumns = props.columns.map(col => {
    if (!col.editable) {
      return col;
    }
    return {
  // 把不需要编辑的那一行依次浅拷贝
      ...col,
  // 重新设置单元格的属性
      onCell: record => ({
        record,
        inputType: 'text',
        dataIndex: col.dataIndex,
        title: col.title,
        requiring: col?.required == false ? false : true,
        selectOptions: col?.selectOptions ? col.selectOptions : null,
        editing: props.isEditing(record),
      }),
    };
  });

  return (
    <Table
    // 	components覆盖默认的 table 元素
      components={{
        body: {
          cell: EditableCell,
        },
      }}
      bordered
      loading={props.loading}
      // dataSource就是需要被展示的值,props是父元素传进来的值,包含了所有引用该组件时传进来的所有值,我们需要展示的值data数据也在其中
      dataSource={props.data}
      scroll={props.scroll}
      columns={mergedColumns}
      // 分页
      pagination={{
        showTotal: (total, range) => `本页${range[1] - range[0] + 1}条,共 ${props.data.length} 条`,
        onChange: props.cancel,
        defaultPageSize: '50',
      }}
      style={props.style}
      size="middle"
      scroll={{ x: '75%', y: 500 }}
      // 多选操作
      rowSelection={{
        onChange: (selectedRowKeys, selectedRows) => {
          props.setSelectedData(selectedRows);
        },
      }}
    />
  );
}

export default EditableTable;
  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值