React + antd实现嵌套可增减表单

2023-11-13

技术栈 React + antd;接到需求,做一个form嵌套表单,刚开始想自己做一个,后来想着参数处理可能比较麻烦就直接用antd的Form吧。

一、目标效果

先看一下效果图

其中点击新增标签及配置时可以加一个红色框里的内容,点击蓝框里的加号可以实现红框里的效果

二、实现

直接上代码,详细解释在里面

import React, { useEffect, useState } from 'react'
// 需要用到的antd组件
import { message, Form, Input, Button, Row, Col, Select, DatePicker, Checkbox, Modal } from "antd";
// 加减删除图标
import { MinusCircleOutlined, PlusCircleOutlined, CloseCircleOutlined } from '@ant-design/icons';
import dayjs from 'dayjs';
import ajax from "@/services";
import './index.scss'

const { RangePicker } = DatePicker;
// 复合嵌套增减表单弹框
const EditLabelModal = (props) => {
  // 接收父组件传来的参数 
  const {
    open = false,            // 弹框是否展示
    id = "",                 // id用于新增和编辑
    labelList = [],          // 标签列表
    onClose = () => { },     // 关闭弹框回调
    onSubmit = () => { }     // 提交表单事件
  } = props
  // 定义form实例
  const [form] = Form.useForm();
  // loading效果,提交时禁用按钮防止重复提交
  const [loading, setLoading] = useState(false)
  // 模拟关联表下拉数据
  const [tableAll, setTableAll] = useState([
    { label: '表1', value: 'b1' },
    { label: '表2', value: 'b2' },
    { label: '表3', value: 'b3' },
    { label: '表4', value: 'b4' },
    { label: '表5', value: 'b5' },
  ])
  // 运算符列表
  const symbolList = [
      {
        label: "大于",
        value: ">"
      },
      {
        label: "大于等于",
        value: ">="
      },
      {
        label: "小于",
        value: "<"
      },
      {
        label: "小于等于",
        value: "<="
      },
      {
        label: "等于",
        value: "="
      },
      {
        label: "不等于",
        value: "!="
      },
      {
        label: "包含",
        value: "like"
      },
      {
        label: "不包含",
        value: "not like"
      },
      {
        label: "不为空",
        value: "is not null"
      },
      {
        label: "为空",
        value: "isnull"
      },
      {
        label: "介于",
        value: ">=<="
      }
    ]
  // 详情数据(用于编辑)
  const [detail, setDetail] = useState({}) // 存一下详情数据
  // 字段列表
  const [fieldList, setFieldList] = useState([
    { label: 'name', value: 'name' },
    { label: 'age', value: 'age' },
    { label: 'time', value: 'time' },
    { label: 'sex', value: 'sex' },
  ]) 
  // 这个是因为运算符后面的内容可能是输入框也可能是日期,这里有date或者time的判断为日期选择器
  const columnRules = /^(?=.*(date|time)).*$/
  // 要改判断的字段在这里改-----↑----↑
  // Form.List默认的小类
  const [baseRules] = useState({ // 添加小类默认值
    column: null,
    symbol: "=",
    value: "",
    value2: "",
    fieldType: "",
    check: false,
    date: "",
  })
  // Form.List默认的大类
  const [baseLabelRules] = useState({ // 添加大类默认值
    labelName: null,
    description: "",
    rules: [baseRules],
  })
  // 根据运算符和前面的字段展示后面的输入框或者日期选择器
  const handleItemInput = (column, symbol) => {
    if (symbol === "is not null" || symbol === "isnull") return <></>
    if (column && columnRules.test(column)) {
      if (symbol === ">=<=") return <RangePicker showTime />
      return <DatePicker showTime />
    }
    return <Input />
  }
  // 处理提交时间(时间还是字符串,一个还是两个)
  const handleSubTime = (item) => {
    const { column, value, value2, symbol, date } = item
    if (symbol == "is not null" || symbol == "isnull") return ""
    if (column && columnRules.test(column)) {
      if (Array.isArray(date)) {
        let times = date.map(i => i.format('YYYY-MM-DD HH:mm:ss')).join(",")
        return times
      }
      return date.format('YYYY-MM-DD HH:mm:ss')
    }
    return value2 ? (value + ',' + value2) : value
  }
  // 处理字段的类型(选择的字段是什么类型的)
  const handleFieldType = (item) => {
    const { fieldType, column } = item
    if (fieldType) return fieldType
    else {
      if (column && Array.isArray(fieldList)) {
        let _fieldType = fieldList.find(i => column == i.label)?.type || ""
        return _fieldType
      }
      else return ""
    }
  }
  // 处理提交规则
  const handleRules = (rules) => {
    let _rules = []
    const baseObj = (obj) => {
      return {
        column: obj?.column || "",
        symbol: obj?.symbol || "",
        value: handleSubTime(obj) || "",
        fieldType: handleFieldType(obj) || ""
      }
    }
    if (Array.isArray(rules) && rules.length) {
      if (rules.length === 1) {
        _rules.push(baseObj(rules[0]))
      } else {
        rules.map((i, index) => {
          if (index === 0) {
            _rules.push(baseObj(i))
          } else if (index === 1) {
            _rules.push(
              {
                column: "",
                symbol: i?.check ? "or" : "and",
                value: "",
                fieldType: ""
              },
              baseObj(i)
            )
          }
        })
      }
    }
    return _rules
  }
  // 整理提交数据结构
  const handleSub = (data) => {
    let _data = { ...data }
    if (Array.isArray(_data.labelRules) && _data.labelRules.length) {
      let _labelRules = []
      _data.labelRules.map(i => {
        _labelRules.push({
          labelName: i.labelName,
          description: i.description,
          rules: handleRules(i.rules)
        })
      })
      _data.labelRules = _labelRules
      return _data
    } else {
      return false
    }
  }
  // 处理编辑时间(回显)
  const handleEditTime = (item) => {
    const { column, value } = item
    let _arr = value ? value.split(",") : []
    if (column && columnRules.test(column)) {
      if (_arr.length == 2) {
        return [dayjs(_arr[0]), dayjs(_arr[1])]
      } else return dayjs(_arr[0])
    }
  }
  // 处理返回编辑的规则(回显)
  const handleEditRules = (rules) => {
    let _rules = []
    if (Array.isArray(rules) && rules.length) {
      if (rules.length === 1) {
        _rules.push(Object.assign({}, baseRules, rules[0]))
      } else {
        rules.map((i, index) => {
          if (index === 0) {
            _rules.push(Object.assign({}, baseRules, i))
          } else if (index === 2) {
            _rules.push(Object.assign({}, baseRules, {
              ...i,
              value: (!columnRules.test(i.column)) ? i.value.split(",")[0] : "",
              value2: (!columnRules.test(i.column)) ? i.value.split(",")[1] : "",
              check: rules[1].symbol === "or" ? true : false,
              date: columnRules.test(i.column) ? handleEditTime(i) : "",
            }))
          }
        })
      }
    }
    return _rules
  }
  // 处理返回来的详情(回显)
  const handleDetailData = data => {
    let _data = { ...data }
    if (Array.isArray(_data.labelRules) && _data.labelRules.length) {
      let _labelRules = []
      _data.labelRules.map(i => {
        _labelRules.push({
          ...i,
          labelName: i.labelName,
          description: i.description,
          rules: handleEditRules(i.rules)
        })
      })
      _data.labelRules = _labelRules
      return _data
    } else {
      return false
    }
  }
  // 保存提交
  const beforeSub = async () => {
    try {
      let data = await form.validateFields()
      let _form = handleSub(data)
      if (!_form) return message.error("至少保留一条标签规则")
      let _sub = Object.assign({}, detail, _form)
      delete _sub.labelModelRuleEntities
      setLoading(true)
      onSubmit(_sub, () => setLoading(false))
    } catch { }
  }
  // 获取所有表(下拉)
  const getAllTable = () => {
    ajax.getLabelModelTable().then(res => {
      if (res.status === 20000) {
        const { data } = res
        if (Array.isArray(data.tableList) && data.tableList.length) {
          setTableAll(data.tableList.map(i => {
            return {
              label: i.tableName,
              value: i.tableName
            }
          }))
        } else {
          setTableAll([])
        }
      } else {
        message.error(res.message)
        setTableAll([])
      }
    }).catch(err => {
      console.log(err)
      setTableAll([])
    })
  }
  // 获取字段列表(下拉)
  const getFieldList = (tableName) => {
    ajax.getLabelModelTableColumn({
      tableName
    }).then(res => {
      if (res.status === 20000) {
        const { data } = res
        if (Array.isArray(data) && data.length) {
          setFieldList(data.map(i => {
            return {
              label: i.name,
              value: i.name,
              type: i.type
            }
          }))
        } else {
          setFieldList([])
        }
      } else {
        message.error(res.message)
        setFieldList([])
      }
    }).catch(err => {
      console.log(err)
      setFieldList([])
    })
  }
  // 获取编辑内容详情
  const getEditInfo = (id) => {
    ajax.getLabelModelEditInfo({
      labelModelId: id
    }).then(res => {
      if (res.status === 20000) {
        let _data = Object.assign({}, res.data)
        setDetail(_data)
        // getFieldList(_data.relevanceTable)
        let formData = handleDetailData(_data)
        form.setFieldsValue(formData)
      }
    }).catch(err => {
      console.log(err)
    })
  }
  // 关联表修改(修改后清空输入值、字段)
  const changeTable = (v) => {
    // getFieldList(v)
    let _f = form.getFieldsValue(true)
    let { labelRules } = _f
    let _labelRules = []
    const handleRules = (rules) => {
      if (Array.isArray(rules) && rules.length) {
        rules.forEach(i => {
          i.column = null
          i.value = ""
          i.value2 = ""
          i.fieldType = ""
          i.date = ""
        })
        return rules
      }
      return []
    }
    if (Array.isArray(labelRules) && labelRules.length) {
      labelRules.map(item => {
        _labelRules.push({
          ...item,
          rules: handleRules(item.rules)
        })
      })
      form.setFieldsValue(Object.assign({}, _f, { labelRules: _labelRules }))
    }
  }
  // 下拉配置
  const selectOption = {
    filterOption: (input, option) => option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
  }
  // 日期、输入框切换报错处理 // antd4.17版本没有setFieldValue方法,就用这个方法处理
  const clearData = (indexs, index, v) => {
    let _f = form.getFieldsValue(true)
    let _value = _f.labelRules[indexs].rules[index].value
    if (v && columnRules.test(v)) {
      if (typeof _value == 'string') _f.labelRules[indexs].rules[index].value = ""
    } else {
      if (typeof _value == 'object') _f.labelRules[indexs].rules[index].value = ""
    }
    form.setFieldsValue(Object.assign({}, _f))
  }

  // 模拟编辑返回的数据
  let f = {
    "labelModelName": "驱蚊的",
    "relevanceTable": "b2",
    "labelRules": [
      {
        "labelName": "l1",
        "description": "",
        "rules": [
          {
            "column": "name",
            "symbol": "=",
            "value": "我的",
            "fieldType": ""
          },
          {
            "column": "",
            "symbol": "or",
            "value": "",
            "fieldType": ""
          },
          {
            "column": "time",
            "symbol": ">=<=",
            "value": "2023-03-01 14:53:50,2023-03-09 14:53:52",
            "fieldType": ""
          }
        ]
      },
      {
        "labelName": "l3",
        "description": "",
        "rules": [
          {
            "column": "age",
            "symbol": ">",
            "value": "23",
            "fieldType": ""
          },
          {
            "column": "",
            "symbol": "and",
            "value": "",
            "fieldType": ""
          },
          {
            "column": "time",
            "symbol": ">",
            "value": "2023-03-27 14:54:17",
            "fieldType": ""
          }
        ]
      }
    ]
  }

  useEffect(() => {
    // 发送请求获取表数据(这里注掉用模拟的)
    // getAllTable()
  }, [])

  useEffect(() => {
    if (!open) {
      // 关闭弹框重置表单
      form.resetFields()
      setDetail({})
      setLoading(false)
      // setFieldList([])
    } else {
      // 打开弹框如果有id就请求详情
      if (id) getEditInfo(id)
      // 这里模拟回显详情数据
      form && form.setFieldsValue(handleDetailData(f))
    }
  }, [open])

  return (
    <Modal
      className='edit-label-modal'
      width={778}
      confirmLoading={loading}
      destroyOnClose={true}
      okText='保存'
      title={`${id ? '编辑' : '新增'}标签模型`}
      open={open}
      onOk={beforeSub}
      onCancel={onClose}
    >
      <Form
        form={form}
        autoComplete="off"
        labelCol={{ span: 6 }}
        wrapperCol={{ span: 16 }}
        disabled={loading} // 整个form表单禁用 antd4.21才有效。。。。
        preserve={false} // 设置false可以实现重置表单
      >
        {/* 顶部的公共信息,没啥好说的 */}
        <Row justify="space-between">
          <Col span={14}>
            <Form.Item
              label="标签模型名称"
              name="labelModelName"
              rules={[{ required: true, message: '请输入标签模型名称' }]}
            >
              <Input placeholder="请输入标签模型名称" />
            </Form.Item>
          </Col>
          <Col span={10}>
            <Form.Item
              name="relevanceTable"
              label="关联表"
              rules={[{ required: true, message: '请选择关联表' }]}
            >
              <Select
                {...selectOption}
                options={tableAll}
                showSearch placeholder="请选择关联表"
                // 选择关联表时做的处理
                onChange={changeTable}
              />
            </Form.Item>
          </Col>
        </Row>
        {/* 关键来了,嵌套表单 */}
        <Form.List
          // 绑定后端要的值
          name="labelRules" 
          // 这里初始化默认值为Form.List大类
          initialValue={[baseLabelRules]} 
        >
          {/* 使用Form.List内置方法 */}
          {(fields, { add, remove }) => (
            // fields Form.List列表
            // add 增加一个
            // remove 删除一个
            <>
              {/* 这里就是一个新增按钮执行add方法 */}
              <Col span={14}>
                <div className="label-rule-box">
                  <span>标签规则</span>
                  <Button type="dashed" ghost onClick={() => {
                    // 获取绑定的labelRules值来限制最多添加多少个
                    const _labelRules = form.getFieldValue('labelRules');
                    if (Array.isArray(_labelRules) && _labelRules.length >= 5) {
                      return message.warning("最多添加五个")
                    }
                    // add方法里加上Form.List大类
                    add(baseLabelRules)
                  }}>
                    新增标签及配置
                  </Button>
                </div>
              </Col>
              {/* 这里注掉了的部分是antd 4.17的写法 */}
              {/* {fields.map((field, indexs) => ( */}
              {/* 下面用的antd 5.x版本 */}
              {fields.map((field) => (
                <div className="rules-main-group" key={field.key}>
                  <Col span={14}>
                    {/* 每一项里面必须这么写才能绑定对提交表单要用的值 */}
                    <Form.Item
                      {...field}
                      // 这个字段用name和key,之前看网上的一些写法用的fieldName,fieldKey,不好使
                      name={[field.name, 'labelName']} 
                      key={[field.key, 'labelName']}
                      label=""
                      rules={[{ required: true, message: '请选择标签' }]}
                    >
                      <Select
                        {...selectOption}
                        options={labelList}
                        showSearch
                        placeholder="请选择标签"
                        fieldNames="label"
                      />
                    </Form.Item>
                  </Col>
                  {/* 大的删除按钮,删除Form.List的一个大类 */}
                  <span className="del-btn" onClick={() => !loading && remove(field.name)}>
                    <CloseCircleOutlined />
                  </span>
                  {/* 嵌套来了,list里面套list */}
                  <Form.List
                    {...field}
                    // 这里面绑定的值就是大类下需要增减的字段名,注意name和key都要加
                    name={[field.name, 'rules']}
                    key={[field.key, 'rules']}
                    // 这里初始化默认值为Form.List小类
                    initialValue={[baseRules]}
                  >
                    {/* 给add和remove重命名使用,避免冲突 */}
                    {(fieldItems, { add: addItem, remove: removeItem }) => (
                      <>
                        {/* 和上面一样进行遍历渲染子form */}
                        {fieldItems.map((fieldItem, index) => {
                          return (
                            <div className="rules-item" key={fieldItem.key}>
                              {/* 这里是有两个表单时展示或、且的选择 */}
                              {fieldItems && fieldItems.length > 1 && (index === fieldItems.length - 1) &&
                                // 这里我用了一个check来做这个点击切换且、或的效果
                                // 使用CheckBox时需要添加一个noStyle再进行勾选
                                <Form.Item
                                  noStyle
                                  shouldUpdate
                                >
                                  {({ getFieldValue }) => {
                                    // 获取当前是否勾选
                                    let check = getFieldValue(['labelRules', field.name, 'rules', fieldItem.name, 'check'])
                                    return <Form.Item
                                      {...fieldItem}
                                      label=""
                                      name={[fieldItem.name, 'check']}
                                      key={[fieldItem.key, 'check']}
                                      // 这里一定要加上,不然不生效
                                      valuePropName="checked"
                                    >
                                      <div className="and-or-btn">
                                        <Checkbox checked={check} />
                                        <span>{check ? '或' : '且'}</span>
                                      </div>
                                    </Form.Item>
                                  }}
                                </Form.Item>
                              }
                              {/* 剩下的就是数据处理了 */}
                              <div className="item-left">
                                <Form.Item
                                  {...fieldItem}
                                  name={[fieldItem.name, 'column']}
                                  key={[fieldItem.key, 'column']}
                                  label=""
                                  rules={[{ required: true, message: '请选择字段' }]}
                                >
                                  <Select
                                    {...selectOption}
                                    options={fieldList}
                                    showSearch
                                    placeholder="请选择字段"
                                    // 这里注掉是之前4.17版本的写法
                                    // onChange={(v) => clearData(indexs, index, v}
                                  />
                                </Form.Item>
                                <Form.Item
                                  {...fieldItem}
                                  name={[fieldItem.name, 'symbol']}
                                  key={[fieldItem.key, 'symbol']}
                                  label=""
                                  rules={[{ required: true }]}
                                >
                                  <Select
                                    {...selectOption}
                                    options={symbolList}
                                    fieldNames="label"
                                    // 这里注掉是之前4.17版本的写法
                                    // onChange={() => clearData(indexs, index)}
                                    onChange={() => form.setFieldValue(['labelRules', field.name, 'rules', fieldItem.name, 'date'], "")}
                                  />
                                </Form.Item>
                              </div>
                              <div className="item-right">
                                <Form.Item
                                  noStyle
                                  shouldUpdate
                                >
                                  {({ getFieldValue }) => {
                                    let _column = getFieldValue(['labelRules', field.name, 'rules', fieldItem.name, 'column'])
                                    let _symbol = getFieldValue(['labelRules', field.name, 'rules', fieldItem.name, 'symbol'])
                                    let isDate = _column && columnRules.test(_column)
                                    if (_symbol === ">=<=" && !(isDate)) {
                                      return <Row gutter={24}>
                                        <Col span={12}>
                                          <Form.Item
                                            {...fieldItem}
                                            name={[fieldItem.name, 'value']}
                                            key={[fieldItem.key, 'value']}
                                            wrapperCol={24}
                                            label=""
                                            rules={[{ required: true, message: '值不能为空' }]}
                                          >
                                            <Input />
                                          </Form.Item>
                                        </Col>
                                        <Col span={12}>
                                          <Form.Item
                                            {...fieldItem}
                                            name={[fieldItem.name, 'value2']}
                                            key={[fieldItem.key, 'value2']}
                                            wrapperCol={24}
                                            label=""
                                            rules={[{ required: true, message: '值不能为空' }]}
                                          >
                                            <Input />
                                          </Form.Item>
                                        </Col>
                                      </Row>
                                    }
                                    return <Form.Item
                                      {...fieldItem}
                                      name={[fieldItem.name, isDate ? 'date' : 'value']}
                                      key={[fieldItem.key, isDate ? 'date' : 'value']}
                                      wrapperCol={24}
                                      label=""
                                      rules={[{ required: true, message: '值不能为空' }]}
                                    >
                                      {handleItemInput(_column, _symbol)}
                                    </Form.Item>
                                  }}
                                </Form.Item>
                              </div>
                              <div className="item-option">
                                {fieldItems && fieldItems.length === 1 &&
                                  <PlusCircleOutlined onClick={() => !loading && addItem(baseRules)} /> ||
                                  <MinusCircleOutlined onClick={() => !loading && removeItem(fieldItem.name)} />
                                }
                              </div>
                            </div>
                          );
                        })}
                      </>
                    )}
                  </Form.List>
                </div>
              ))}
            </>
          )}
        </Form.List>
      </Form>
    </Modal >
  )
}

export default EditLabelModal

总结

以上就是一个完整的demo例子,实现的最主要关键就在于要使用 name 和 key 来绑定值,其他的都是按照项目具体需求去改,有问题的话希望不吝赐教,感谢

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React + antd实现嵌套可增减表单 的相关文章

随机推荐

  • 微芯I/O控制器瞄准工业与嵌入式运算应用

    微芯科技 Microchip Technology 日前发布SCH322X系列I O控制器新品 该系列产品基于工业及嵌入式开发工程师的需求而开发 功能丰富且具高灵活性 新一代I O控制器系列拥有尺寸更小的包装和更长的产品生命周期 可运用于更
  • caj转pdf

    https caj2pdf cn
  • 关于不同浏览器的内核与引擎--记录一下

    https www cnblogs com gdutbean archive 2012 02 21 2362003 html https www cnblogs com guanghe p 11719334 html js引擎介绍 几种JS
  • Docker: 改变容器化世界的革命性技术

    目录 1 1什么是虚拟化 1 2什么是Docker 1 3容器与虚拟机的比较 1 4Docker组建 2 Docker安装 2 2设置ustc的镜像 2 3Docker的启动与停止 3 docker常用命令 3 1镜像 3 2容器相关命令
  • Dockerfile参数详解

    FROM 功能为指定基础镜像 并且必须是第一条指令 如果不以任何镜像为基础 那么写法为 FROM scratch 同时意味着接下来所写的指令将作为镜像的第一层开始 语法 FROM
  • discuz 手机版伪静态

    前两天发布的这篇文章发现内容与实际情况不太相符特来更改 请多多包涵 网上有些现成的插件 价格却并不亲民 一个简简单单的伪静态插件居然标价三百 我也是醉了 我就在想 伪静态翻来覆去不就那么点东西吗 你能做我就做不了啦 在此帮各位仍有相同需求的
  • BP神经网络基本介绍

    1 主要解决的是什么问题 预测类 聚类分析 2 原理 思路是啥 什么是人工神经网络 ANN 模拟大脑对信号处理的一种算法 基本原理介绍 权关系是具体不清楚他们之间的关系 并未给出准确的对应关系 只是假设他们之间的关系可以用一组权来表示 阈值
  • 企业DevOps:实施过程中需要关注的各项要点

    作者 亚马逊云科技企业市场战略总监 Stephen Orban 经验并非凭空创造 而是依靠点滴积累所实现 阿尔贝 加缪 在此次的企业DevOps探索之旅系列文章当中 我将带大家一同探讨企业在具备一定DevOps经验之后又该如何处理下一步可能
  • BlockingQueue、ArrayBlockingQueue、LinkedBlockingQueue原理分析

    阻塞队列与非阻塞队 阻塞队列与普通队列的区别在于 当队列是空的时 从队列中获取元素的操作将会被阻塞 或者当队列是满时 往队列里添加元素的操作会被阻塞 试图从空的阻塞队列中获取元素的线程将会被阻塞 直到其他的线程往空的队列插入新的元素 同样
  • MySQL数据库定时备份脚本

    bin bash 定义备份用户 密码 DbUser root DbPasswd NTQ12377 定义备份数据库 DbName zabbix jumpserver openfire n9e n9e v5 ibex 定义备份目录 Path d
  • 手把手带你编写微信公众号

    这是一个简单的项目 简单编写微信公众号 扫码关注 关注 即可提高学习效率 Peace 实时查询城市天气 回复 美女视频网站 观看美女视频 不定时推送小姐姐视频和图片合集 Docker线上部署SpringBoot 如果您不知道如何开始编写的话
  • ajax中设置contentType: “application/json”的作用

    最近在做项目交互的时候 刚开始向后台传递数据返回415 后来百度添加了 contentType application json 之后返回400 然后把传输的数据格式改为json字符串就传输成功了 现在我们来看看 contentType a
  • Keras-训练网络时的问题:loss一直为nan,accuracy一直为一个固定的数

    目录 问题描述 问题的解决 调整学习率后解决问题 其他可能导致此问题的原因 1 2 3 4 关于如何选择学习率 问题描述 在使用VGG19做分类任务时 遇到一个问题 loss一直为nan accuracy一直为一个固定的数 如下输出所示 即
  • ESP32-C3入门教程 网络 篇(三、 MQTT 协议基础介绍及测试)

    在前面 我们已经学会了 ESP32 C3 的WiFi 配置以及使用 为我们学习网络协议建立了基础 这篇文章我们就来学习测试一下ESP32 C3 的 MQTT 驱动 目录 前言 1 基础介绍 1 1 MQTT协议基本概念 1 2 ESP MQ
  • c#实现循环输入商品编号和购买数量,结账时应付金额并找零

    循环输入商品编号和购买数量 系统自动计算每种商品的价钱 单价X数量 并累加总金额 当输入n时结账 假设享受8折优惠 结账时 根据折扣计算应付金额 输入实付金额 并找零 下面展示一些 内联代码片 使用c 实现 代码如下 An highligh
  • 【数据压缩3】AVI文件格式分析及问题回答+WAV文件格式分析

    目录 AVI文件问题回答 1 AVI文件音频和视频的数据是如何放置的 交织放置还是连续放置 2 AVI文件一个视频帧大约占据多少字节 一个音频数据块大约占用多少字节 WAV文件格式分析 文件概述 文件格式 RIFF区块 FORMAT区块 D
  • 数据结构——根据后序遍历结果和中序遍历结果画出二叉树

    根据二叉树的中序和后序遍历结果画出二叉树 1 首先根据后序遍历结果判断根节点 最右边的元素 2 在中序遍历结果中找到该根节点 该节点的左边为根节点的左子树 节点右边为根节点的右子树 3 回到后序遍历中找点左子树在后序遍历中最右边的元素即为左
  • FPGA学习方向规划

    前言 仅以本帖 记录自己的学习历程及未来的方向 刚入职做FPGA研发1年 也不知道自己的发展方向 所以 从FPGA接口通信入手 慢慢学习和了解吧 希望自己逐步积累和掌握以下几个方向从业的基础知识 并具有一定的研发能力 主要方向分以下个方向
  • Binning模式缩小分辨率

    示例 640 480 NV12图像 提取Y部分数据 将Y数据做降采样 隔行隔列取值 保存成文件 include
  • React + antd实现嵌套可增减表单

    技术栈 React antd 接到需求 做一个form嵌套表单 刚开始想自己做一个 后来想着参数处理可能比较麻烦就直接用antd的Form吧 一 目标效果 先看一下效果图 其中点击新增标签及配置时可以加一个红色框里的内容 点击蓝框里的加号可