Ant Design 使用Tabs和Form.List 实现二维数组结构

使用场景与实现效果

需求的数据结构为可编辑的二维数组结构,在Form表单中提交数据到服务端,下面为数据结构的例子:

[
	[{
		"text": "",
		"audioUrl": "",
		"emotion": ""
	}, {
		"text": "",
		"audioUrl": "",
		"emotion": ""
	}],
	[{
		"text": "",
		"audioUrl": "",
		"emotion": ""
	}, {
		"text": "",
		"audioUrl": "",
		"emotion": ""
	}]
]

实现效果:实现元素的动态添加,包含音频的上传与播放

Ant Design 使用Tabs和Form.List 实现二维数组结构_第1张图片

实现思路

在Form表单组件中使用Tabs标签页组件(数据为第一层数组),然后再Tabs选项卡组件中使用Form.List组件(数据为第二层数组),最终提交Form表单获取想要的数据结构。

实现代码

import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import {
  Tabs,
  Form,
  Row,
  Col,
  Divider,
  Input,
  Select,
  Button,
  Upload,
  message
} from "antd";
import {
  MinusCircleOutlined,
  PlusOutlined,
  UploadOutlined,
  SoundTwoTone
} from "@ant-design/icons";

const { TabPane } = Tabs;

const formItemLayout = {
  labelCol: { span: 4 },
  wrapperCol: { span: 14 }
};

// 音频样式
const formItemYin = {
  labelCol: { span: 4 },
  wrapperCol: { span: 20 }
};

const initialPanes = [
  { title: "方案1", key: "1" },
  { title: "方案2", key: "2" },
  { title: "方案3", key: "3" }
];

const initialForm = {
  data1: [
    {
      audioUrl: "",
      text:
        "因为怕水痘乘着风就跑到别人身上去了呀#哈哈大笑#这样我就不痒了,别人痒。",
      emotion: "Default"
    }
  ],
  data2: [
    { audioUrl: "", text: "哈哈大笑#这样我就不痒了,别人痒。", emotion: "sad" }
  ],
  data3: [{ audioUrl: "", text: "因为怕水痘乘着风就跑到", emotion: "angry" }]
};

class Demo extends React.Component {
  newTabIndex = 0;

  state = {
    activeKey: initialPanes[0].key,
    panes: initialPanes,
    formValues: initialForm
  };

  formRef = React.createRef();

  // tab 改变触发
  onChange = (activeKey) => {
    this.setState({ activeKey });
  };

  // tab 修改触发
  onEdit = (targetKey, action) => {
    this[action](targetKey);
  };

  // tab 新增触发
  add = () => {
    const { panes } = this.state;
    const activeKey = panes.length + 1;
    const newPanes = [...panes];
    newPanes.push({
      title: "方案" + activeKey,
      key: activeKey.toString()
    });
    this.setState({
      panes: newPanes,
      activeKey: activeKey.toString()
    });
  };

  // tab 移除触发
  remove = (targetKey) => {
    const { panes, activeKey } = this.state;
    let newActiveKey = activeKey;
    let lastIndex = 0;
    panes.forEach((pane, i) => {
      if (pane.key === targetKey) {
        lastIndex = i - 1;
      }
    });
    const newPanes = panes.filter((pane) => pane.key !== targetKey);
    if (newPanes.length && newActiveKey === targetKey) {
      if (lastIndex >= 0) {
        newActiveKey = newPanes[lastIndex].key;
      } else {
        newActiveKey = newPanes[0].key;
      }
    }
    this.setState({
      panes: newPanes,
      activeKey: newActiveKey
    });
  };

  // 提交form 表单
  onFinish = (values) => {
    console.log(values);
  };

  // 上传组件触发
  handleChange(info, index) {
    if (info.file.status === "uploading") {
      console.log("正在上传");
    }
    if (info.file.status !== "uploading") {
      console.log(info.file, info.fileList);
    }
    if (info.file.status === "done") {
      if (info.file.response.result === true) {
        console.log(info.file.response.message);
        this.formRef.current.setFields([
          { name: index, value: info.file.response.message }
        ]);
      } else {
        message.error(`上传失败:${info.file.response.message}.`);
      }
      message.success(`${info.file.name} 上传成功`);
    } else if (info.file.status === "error") {
      message.error(`${info.file.name}上传失败.`);
    }
  }

  // 多媒体播放/暂停
  handleAudio = (index) => {
    var audio = document.getElementById("audio");
    if (audio && audio.src) {
      if (audio.src === this.formRef.current.getFieldValue(index)) {
        // 当前的资源
        if (audio.paused) {
          audio.play(); // 这个就是播放
        } else {
          audio.pause(); // 这个就是暂停
        }
      } else {
        // 存在src 但不是当前点击的资源,则播放当前资源
        audio.src = this.formRef.current.getFieldValue(index);
        audio.play();
      }
    } else {
      // 没有音频路径 则是播放
      audio && (audio.src = this.formRef.current.getFieldValue(index));
      audio && audio.play();
    }
  };

  // 手动录入音频地址   拆分出音频名称
  handleSelf = (e) => {
    if (e.target.value) {
      const a = e.target.value.split("/");
      if (a && a.length > 0) {
        console.log("name", a[a.length - 1]); // 上传音频后更新节点标题名称
      } else {
        message.warning("请输入正确的音频地址");
      }
    }
  };

  render() {
    const { panes, activeKey, formValues } = this.state;
    return (
      <>
        
        
{panes.map((pane) => ( {(fields, { add, remove }) => { return (
{fields.map((field, index) => ( <> 简单对话{index + 1}    { remove(field.name); }} /> this.handleSelf(e)} /> this.handleChange(info, [ `data${pane.key}`, index, "audioUrl" ]) } > this.handleAudio([ `data${pane.key}`, index, "audioUrl" ]) } /> ))}
); }}
))}
); } } ReactDOM.render(, document.getElementById("container"));

部分功能记录

1、Form.List中的音频上传成功后,回显到对应的输入框中

this.handleChange(info,[`data${pane.key}`,index, 'audioUrl'])}
                                                    >



// 上传组件触发
    handleChange (info:any,  index:any){
        if (info.file.status === 'uploading') {
          console.log("正在上传")
        }
        if (info.file.status !== 'uploading') {
          console.log(info.file, info.fileList);
        }
        if (info.file.status === 'done') {
          if(info.file.response.result === true){
            console.log(info.file.response.message);
            this.formRef.current.setFields([{name:index,value:info.file.response.message}])
          }else{
            message.error(`上传失败:${info.file.response.message}.`);
          }
          message.success(`${info.file.name} 上传成功`);
        } else if (info.file.status === 'error') {
          message.error(`${info.file.name}上传失败.`);
        }
    }

this.formRef.current.setFields([{name:index,value:info.file.response.message}])   实现上传后的回显

你可能感兴趣的:(Ant,Design,reactjs)