最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

react antd實(shí)現(xiàn)動(dòng)態(tài)增減表單

 更新時(shí)間:2021年06月03日 15:34:30   作者:月亮出來了  
antd是react流行的ui框架庫,本文主要介紹了react antd實(shí)現(xiàn)動(dòng)態(tài)增減表單,分享給大家,感興趣的小伙伴們可以參考一下

之前寫動(dòng)態(tài)表單遇到過坑,就是用index下標(biāo)做key會(huì)導(dǎo)致bug,而且很嚴(yán)重!

今天有空寫下文章記錄下:怎么處理和邏輯

我用的是antd3的版本,3和4的表單有點(diǎn)不一樣,不過差別應(yīng)該不大。

需求:

1、選擇類型切換展示固定的模板

2、通過新增字段可以動(dòng)態(tài)增減表單里面的每一行

3、控制每一行的字段是否需要必填

4、編輯時(shí)候回填參數(shù)

效果圖:

部分關(guān)鍵代碼:

import React, { Component } from 'react';
import styles from './index.less';
import {
  Table,
  Button,
  Select,
  Popconfirm,
  Modal,
  Form,
  Input,
  Radio,
  Row,
  Col, Tooltip,
  Icon,
  message,
  Pagination, InputNumber,
} from 'antd';

const Option = Select.Option;
const FormItem = Form.Item;

let id = 0;

@Form.create()
class Index extends Component {
  marketId = 0;
  state = {
    selectType: '',
    orderType: 1,  //文章1  地圖2
    typeLoading: false,
    isEdit: false,
    lookVisible: false,
    visible: false,
    pageSize: 10,
    pageNum: 1,
    keyWord: '',
    row: {},
    typeList: {},
    mock: {},
    mapType: [{
      'fieldName': 'name',
      'isImg': 0,
      'order': 0,
      'remarks': '名稱',
    }, {
      'fieldName': 'label',
      'isImg': 0,
      'order': 0,
      'remarks': '標(biāo)簽',
    }, {
      'fieldName': 'lon',
      'isImg': 0,
      'order': 0,
      'remarks': '經(jīng)度',
    }, {
      'fieldName': 'lat',
      'isImg': 0,
      'order': 0,
      'remarks': '緯度',
    }],
    articleType: [{
      'fieldName': 'name',
      'isImg': 0,
      'order': 0,
      'remarks': '名稱',
    }, {
      'fieldName': 'label',
      'isImg': 0,
      'order': 0,
      'remarks': '標(biāo)簽',
    }],
  };
/**
   * 將動(dòng)表單態(tài)值生成需要的數(shù)據(jù)格式
   * @param values
   * @returns {[]}
   */
  createValues = (values) => {
    const { row } = this.state;
    const data = [];
    const newValues = { // 用新的對象承載提交的數(shù)據(jù)
      ...values,
    };
    const fieldNameData = []; // 保存fieldName值
    const remarksData = []; // 保存remarks值
    const isImgData = []; // 保存isImg值
    const orderData = []; // 保存orderData值
    const fieldName = RegExp(/fieldName/);
    const remarks = RegExp(/remarks/);
    const isImg = RegExp(/isImg/);
    for (const key in newValues) {
      if (fieldName.test(key)) {
        fieldNameData.push(newValues[key]);
      }
    }
    for (const key in newValues) {
      if (remarks.test(key)) {
        remarksData.push(newValues[key]);
      }
    }
    for (const key in newValues) {
      if (isImg.test(key)) {
        isImgData.push(newValues[key]);
      }
    }
    for (const key in newValues) {
      if (isImg.test(key)) {
        orderData.push(newValues[key]);
      }
    }
    fieldNameData.forEach((item, index) => {
      data.push({
        fieldName: item,
        remarks: remarksData[index],
        isImg: isImgData[index],
        order: orderData[index],
        id: row.dataType ? row.dataType.id : '',
      });
    });
    return data;
  };

  handleOk = e => {
    this.props.form.validateFields((err, values) => {
      if (!err) {
        const { row, isEdit } = this.state;
        const params = {
          dataType: {
            name: values.name,
            type: values.type,
            id: row.dataType ? row.dataType.id : '',
          },
          typeFields: [],
        };
        params.typeFields = this.createValues(values);
        if (isEdit) {
          editType(params).then(res => {
            if (res.code === 0) {
              message.info('修改成功');
              this.setState({
                visible: false,
                isEdit: false,
              });
              this.fetchTypeList();
              this.props.form.resetFields();
            }
          });
        } else {
          addType(params).then(res => {
            if (res.code === 0) {
              message.info('新增成功');
              this.setState({
                visible: false,
                isEdit: false,
              });
              this.fetchTypeList();
              this.props.form.resetFields();
            }
          });
        }
      }
    });
  };

  lookOrEditTypeModal = (flag, record) => {
    const { articleType, mapType } = this.state;
    if (flag === 'add') {  //添加默認(rèn)為文章模板
      this.marketId = articleType.length + 1;  //設(shè)置動(dòng)態(tài)key標(biāo)記長度
      this.setState({
        visible: true,
        row: { typeFields: articleType },
      });
    } else if (flag === 'edit') {
      this.setState({
        visible: true,
      });
      getType({ dataTypeId: record.id }).then(res => {
        if (res.code === 0) {
          this.marketId = res.data.typeFields.length + 1;  //設(shè)置動(dòng)態(tài)key標(biāo)記長度
          this.setState({
            row: res.data,
            isEdit: flag === 'edit',
          });
        }
      });
    } else {
      this.setState({
        lookVisible: true,
      });
      getType({ dataTypeId: record.id }).then(res => {
        if (res.code === 0) {
          this.setState({
            row: res.data,
          });
        }
      });
    }
  };


  onChangeType = (value) => {
    const { form } = this.props;
    const { orderType, row, articleType, mapType } = this.state;
    this.props.form.resetFields();

    const params = {};
    if (value === 1) {  //文章類型
      params['typeFields'] = articleType;
      this.marketId = articleType.length + 1;
    } else {
      params['typeFields'] = mapType;
      this.marketId = mapType.length + 1;
    }
    this.setState({
      row: params,
      orderType: value,
    });
  };
//刪除方法?。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。?!
  removeFile = k => {
    const { form } = this.props;
    const keys = form.getFieldValue('keys');
    if (keys.length === 1) {
      return;
    }
    form.setFieldsValue({
      keys: keys.filter(key => key !== k),
    });
  };
//添加方法?。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。?!
  addFile = () => {
    const { form } = this.props;
    const keys = form.getFieldValue('keys');
    const nextKeys = keys.concat(this.marketId++);
    form.setFieldsValue({
      keys: nextKeys,
    });
  };

  judgeIsTemplet = (data) => {
    if (!data) {
      return false;
    }
    if ((data.fieldName === 'lat') || (data.fieldName === 'lon') || (data.fieldName === 'label') || (data.fieldName === 'name')) {
      return true;
    }
  };
  handleValidator = (rule, val, callback) => {
    if (!val) {
      callback();
    }
    let validateResult = /^[5A-Za-z0-9-\_]+$/.test(val);
    if (!validateResult) {
      callback('請輸入正確表字段');
    }
    callback();
  };

  columns = [
    {
      title: '類型名稱',
      dataIndex: 'name',
      key: 'name',
      width: 500,
    },
    {
      title: '所屬類型',
      dataIndex: 'type',
      key: 'type',
      render: (text) => {
        return text === 1 ? '文章' : '地圖';
      },
    },
    {
      title: '操作',
      dataIndex: 'address',
      key: 'address',
      render: (text, record) => {
        return <div>
          <Button type='link' onClick={() => this.lookOrEditTypeModal('look', record)}>查看</Button>
          <Button type='link' onClick={() => this.lookOrEditTypeModal('edit', record)}>編輯</Button>
          <Popconfirm title="確認(rèn)刪除?" onConfirm={() => this.deleteTypeClick(record)}>
            <Button type='link'>刪除</Button>
          </Popconfirm>
        </div>;
      },
    },
  ];

  render() {
    const { selectType, typeLoading, mock, row, isEdit, typeList, keyWord, lookVisible } = this.state;
    const { getFieldDecorator, getFieldValue } = this.props.form;
    let typeFields = row.typeFields || [];
    const initData = [];
    typeFields.forEach((item, index) => {//根據(jù)真實(shí)數(shù)據(jù),設(shè)置默認(rèn)keys數(shù)組
      initData.push(index);
    });
    getFieldDecorator('keys', { initialValue: initData });  //給表單增加keys字段,并設(shè)置默認(rèn)值,這里編輯時(shí)候可以生成編輯回填的效果。
    const keys = getFieldValue('keys');
    const formItems = keys.map((k) => (
      <Row gutter={12} key={k} className={styles.form_row}>
        <FormItem label="字段" key={`fieldName_${k}`}>
          {getFieldDecorator(`fieldName_${k}`, {
            initialValue: row.typeFields[k] ? row.typeFields[k].fieldName : '',
            validateTrigger: ['onChange', 'onBlur'], //校驗(yàn)子節(jié)點(diǎn)值的時(shí)機(jī)
            rules: [{
              required: true,
              message: '請輸入英文字段!',
            }, {
              validator: this.handleValidator,
            }],
          })(<Input placeholder="請輸入英文字段" max={30} disabled={this.judgeIsTemplet(row.typeFields[k])}/>)}
        </FormItem>
        <FormItem label="名稱" key={`remarks_${k}`}>
          {getFieldDecorator(`remarks_${k}`, {
            initialValue: row.typeFields[k] ? row.typeFields[k].remarks : '',
            validateTrigger: ['onChange', 'onBlur'],
            rules: [{
              required: true,
              message: '請輸入中文名稱!',
            }],
          })(<Input placeholder="請輸入中文名稱" disabled={this.judgeIsTemplet(row.typeFields[k])}/>)}
        </FormItem>
        <FormItem label="排序" key={`order_${k}`}>
          {getFieldDecorator(`order_${k}`, {
            initialValue: row.typeFields[k] ? row.typeFields[k].order : 0,
          })(<InputNumber style={{width:75}} placeholder="排序" />)}
        </FormItem>
        <FormItem label="圖片" key={k}>
          {getFieldDecorator(`isImg_${k}`, {
            initialValue: row.typeFields[k] ? row.typeFields[k].isImg : 0,
            rules: [{
              required: true,
            }],
          })(<Radio.Group disabled={this.judgeIsTemplet(row.typeFields[k])}>
            <Radio value={0}>否</Radio>
            <Radio value={1}>是</Radio>
          </Radio.Group>)}
        </FormItem>
        {!this.judgeIsTemplet(row.typeFields[k]) ? (
          <Icon type="minus-circle" onClick={() => this.removeFile(k)} title='刪除'/>
        ) : null}
      </Row>
    ));


    return (
      <div className={styles.wrap_type}>
        <Modal
          title="類型管理"
          visible={this.state.visible}
          onOk={this.handleOk}
          onCancel={this.handleCancel}
          width={890}
          // className={styles.modal_type}
          maskClosable={false}
        >
          <Form layout='inline'>
            <Row style={{ textAlign: 'center', marginBottom: 14 }}>
              <FormItem label="選擇類型">
                {getFieldDecorator('type', {
                  initialValue: row.dataType ? row.dataType.type : 1,
                  rules: [{
                    required: true,
                  }],
                })(<Select onChange={this.onChangeType} disabled={isEdit} style={{ width: 200 }}>
                  <Option value={1}>文章類型</Option>
                  <Option value={2}>地圖類型</Option>
                  <Option value={3} disabled={true}>文件類型</Option>
                </Select>)}
              </FormItem>
              <FormItem label="類型名稱">
                {getFieldDecorator('name', {
                  initialValue: row.dataType ? row.dataType.name : '',
                  rules: [{
                    required: true,
                    message: '請輸入類型名稱!',
                  }],
                })(<Input placeholder="請輸入類型名稱" style={{ width: 200 }}/>)}
              </FormItem>
            </Row>
            {formItems}
            <div style={{ margin: 'auto', textAlign: 'center' }}>
              <Button icon="plus" onClick={this.addFile} style={{ marginTop: 10 }}>新增字段</Button>
            </div>
          </Form>
        </Modal>
      </div>
    );
  }
}

export default Index;

關(guān)鍵地方是設(shè)置一個(gè)marketID作為動(dòng)態(tài)添加的key,然后用他的值作為動(dòng)態(tài)key。(千萬不要用數(shù)組的下標(biāo)index來作為key)!

到此這篇關(guān)于react antd實(shí)現(xiàn)動(dòng)態(tài)增減表單的文章就介紹到這了,更多相關(guān)react antd動(dòng)態(tài)增減表單內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • React的Props、生命周期詳解

    React的Props、生命周期詳解

    “Props” 是 React 中用于傳遞數(shù)據(jù)給組件的一種機(jī)制,通常作為組件的參數(shù)進(jìn)行傳遞,在 React 中,props 是只讀的,意味著一旦將數(shù)據(jù)傳遞給組件的 props,組件就不能直接修改這些 props 的值,這篇文章主要介紹了React的Props、生命周期,需要的朋友可以參考下
    2024-06-06
  • React中Suspense及l(fā)azy()懶加載及代碼分割原理和使用方式

    React中Suspense及l(fā)azy()懶加載及代碼分割原理和使用方式

    這篇文章主要介紹了React中Suspense及l(fā)azy()懶加載及代碼分割原理和使用方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • react-native滑動(dòng)吸頂效果的實(shí)現(xiàn)過程

    react-native滑動(dòng)吸頂效果的實(shí)現(xiàn)過程

    這篇文章主要給大家介紹了關(guān)于react-native滑動(dòng)吸頂效果的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用react-native具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • 基于React編寫一個(gè)全局Toast的示例代碼

    基于React編寫一個(gè)全局Toast的示例代碼

    前些日子在做項(xiàng)目的時(shí)候,需要封裝一個(gè)Toast組件,我想起之前用過的庫,只要在入口文件中引入就可以在全局中使用,還是很方便的,借這次機(jī)會(huì)也來實(shí)現(xiàn)一下,所以本文介紹了React中如何編寫一個(gè)全局Toast,需要的朋友可以參考下
    2024-05-05
  • react項(xiàng)目中redux的調(diào)試工具不起作用的解決

    react項(xiàng)目中redux的調(diào)試工具不起作用的解決

    這篇文章主要介紹了react項(xiàng)目中redux的調(diào)試工具不起作用的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • 淺談React底層實(shí)現(xiàn)原理

    淺談React底層實(shí)現(xiàn)原理

    本文主要介紹了淺談React底層實(shí)現(xiàn)原理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • React中的合成事件是什么原理

    React中的合成事件是什么原理

    React 中的事件,是對原生事件的封裝,叫做合成事件。這篇文章主要通過幾個(gè)簡單的示例為大家詳細(xì)介紹一下React中的合成事件,感興趣的可以了解一下
    2023-02-02
  • React優(yōu)化子組件render的使用

    React優(yōu)化子組件render的使用

    這篇文章主要介紹了React優(yōu)化子組件render的使用,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-05-05
  • React 原理詳解

    React 原理詳解

    這篇文章主要介紹了深入理解react的原理,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2021-10-10
  • React實(shí)現(xiàn)類似淘寶tab居中切換效果的示例代碼

    React實(shí)現(xiàn)類似淘寶tab居中切換效果的示例代碼

    這篇文章主要介紹了React實(shí)現(xiàn)類似淘寶tab居中切換效果,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06

最新評論

广昌县| 龙井市| 凌云县| 固镇县| 高清| 新巴尔虎右旗| 盱眙县| 仁寿县| 安乡县| 长宁县| 鹤山市| 台山市| 桐柏县| 乌海市| 合水县| 宕昌县| 和平县| 张家港市| 太谷县| 五家渠市| 娄烦县| 石渠县| 姜堰市| 麻栗坡县| 钦州市| 平度市| 如东县| 耿马| 临夏市| 丽水市| 枣强县| 左贡县| 建湖县| 望谟县| 房山区| 枣庄市| 固安县| 松潘县| 乐安县| 思南县| 镇坪县|