Ant Design在处理业务表单中的一些实践

news2024/11/20 11:25:25

文章目录

    • 前言
    • 表单处理实践
      • Modal 清空旧数据
      • 使用Form.create和getFieldDecorator对Form进行包装
      • 表单控件是switch
      • 自定义表单控件
      • Table列表
      • Select
      • showSearch 用于在选择框中显示搜索框
      • 其他需要注意的组件
        • Tabs
    • 其它

前言

目前,很多中小企业前端实现采用了react+antd技术栈。在传统业务中,大部分后台的表单和列表模式类似,通过antd组件快速搭建,可以节约时间成本。本文是实际场景中的一些实践记录,供大家参考。

表单处理实践

Modal 清空旧数据

组件有标准的 React 生命周期,关闭后状态不会自动清空。 如果希望每次打开都是新内容,需要自行手动清空旧的状态。或者打开时给 Modal 设置一个全新的 key, React 会渲染出一个全新的对话框。

第一种清空方式:显示弹窗时设置一个新的key

 componentWillReceiveProps(nextprops){
    //打开时设置一个新key
    if(nextprops.visible)
       this.setState({newKey:!this.state.newKey})
  }
  <Modal key={this.state.newKey} visible={this.props.visible} />

第二种清空方式:关闭弹窗后,清空弹窗数据,弹窗内是表单时重置表单。

afterClose = () => {
     // 隐藏动画完成后重置内容
     this.props.form.resetFields();
 }
 <Modal afterClose={this.afterClose} visible={this.props.visible} />

使用Form.create和getFieldDecorator对Form进行包装

经过包装的Form具备以下特点:

使用 Form.create 处理后的表单具有自动收集数据并校验的功能;
不再需要用 onChange 来做同步,但还是可以继续监听 onChange 等事件;
不能用控件的 value或defaultValue 等属性来设置表单域的值,默认值可以用 getFieldDecorator 里的 initialValue;
不需要用 setState,可以使用 this.props.form.setFieldsValue 来动态改变表单值,使用 this.props.form.getFieldsValue来获取表单值。
包装一个表单包括三个步骤:
第一步:

class CustomizedForm extends React.Component {}

CustomizedForm = Form.create({})(CustomizedForm);

第二步:使用getFieldDecorator装饰对应的field

const FormItem = Form.Item;
const formItemLayout = {
      labelCol: { span: 5 },
      wrapperCol: { span: 12 }
};
<Form onSubmit={this.submit}>
    <FormItem {...formItemLayout} label={'名称'}>
        {getFieldDecorator('fieldName', {
            //rules是表单的校验规则
            rules: [{ required: true, message: '请填写表单字段!' }],
            initialValue:'初始值'
          })(
            <Input />
          )}
    </FormItem>
</Form>

第三步:submit时添加校验逻辑和后处理

submit = (e)=> {
    //这里去掉默认行为,可以避免用户操作回车时提交表单
    e.preventDefault();
    //校验表单的值
    this.props.form.validateFields((err, values) => {
      if (!err) {
        //后处理操作
      }
   }
}

表单控件是switch

switch开关的值参数名是checked而不是value,使用时有两种方式:
第一种:引入团队封装后的switch控件

tnpm install @ali/uniform-react-components --save
import Switch from ‘@ali/uniform-react-components/lib/Switch/index’;
第二种: 使用valuePropName

<FormItem {…formItemLayout} label=“Switch” > {getFieldDecorator(‘switch’, { valuePropName: ‘checked’ })( )}

自定义表单控件

自定义表单控件的需求场景很多,为了能够支持 antd Form 的 getFieldDecorator 包装,从而使组件能直接用于 Form 中,需要遵守以下规则:

提供受控属性 value 或其它与 valuePropName 的值同名的属性。
提供 onChange 事件或 trigger 的值同名的事件。
不能是函数式组件。
大CMS业务中用到的自定义表单控件有很多,例如UploadImg,TreeSelect,BizTypeSelect等等,具体可以参考youku-manager和youku-scg等工程里面的实践。

Table列表

第一步:定义columns 即列表中列的描述

columns = [{
    title: 'ID',
    dataIndex: 'id',
    key: 'id'
  }, {
    title: '内容数量',
    key: 'amount',
    //render用于生成复杂数据的渲染函数,参数分别为当前行的值,当前行数据
    render: (text,record) => <a onClick={()=>this.relationTagPopup(record)}>查看</a>,
  },{
    title: '操作',
    key: 'action',
    //删除,下线等post操作使用PopConfirm进行二次确认
    render: (item) => (
      <div>
        <a onClick={() => this.editTag(item)}>编辑</a>
        <span className='ant-divider'></span>
        <Popconfirm title="确定删除吗?" onConfirm={()=>this.deleteTag(item)}>
           <a>删除</a>
        </Popconfirm>
      </div>
    )
  }];

第二步:定义Table
rowKey属性是表格行 key 的取值,这里取的是column中的id字段,保证key值不重复
loading表示页面是否加载中,在翻页和查询时添加load效果,可以优化体验
dataSource 数据数组

<Table columns={this.columns} loading={state.loading} dataSource={state.tagList} pagination={{ pageSize:10, total: state.total, current: state.pageNo, }} onChange={this.handlePagination} rowKey="id" />

第三步:更新dataSource数据源

this.setState({loading:true})
IO.getTagRepertoryList(data)
      .then(response => {
        if(response.success){
          const data = response.data;
          const tagList = data.itemList;
          const total = data.totalSize;
          const pageNo =  data.pageNo;
          const loading = false;
          this.setState({tagList,pageNo,total,loading});
        }
        else{
          Message.warning(response.message)
          this.setState({
            tagList:[],
            total:0,
            pageNo:1,
            loading:false
          });
        }
      })
      .catch(err => {
        console.error(err);
         this.setState({
           loading:false,
           tagList:[],
           total:0,
           pageNo:1,
         });
         Message.error('查询异常,无结果');
      });

Select

cms后台的业务有很多选择选择下拉需求,下面两个业务常见的select为例,解释几个比较重要的配置

多值远程搜索
screenshot.png

screenshot.png

render() { 
//fetching 查询状态,用于在接口数据返回前显示loading效果 
const { fetching, personList } = this.state; 
// Option的name属性对应的是optionLabelProp设置的值 
const options = personList.map((d,index)=> 
    <Option key={index} value={(d.id).toString()} 
    name={d.name}> 
    <div className='person-item-img'><img src={d.thumbUrl} />
    </div> 
	<span className='person-item'>{d.name}</span> 
	<span className='person-item'>{d.birthday}</span> 
</Option>) 
return ( <div className='person-search'> 
	<Select defaultValue={this.props.defaultVal} 
	       mode="multiple" placeholder="输入相关人物名称检索选择" 
	       notFoundContent={fetching ? <Spin size="small" /> : null} 
	       optionLabelProp='name' filterOption={false} 
	       onSearch={this.fetchUser} 
	       onChange={this.handleChange} 
	       onFocus={this.fetchUser} style={{ width: '100%' }} 
	       labelInValue > 
	    {options} 
	</Select> 
	</div> 
) 

optionLabelProp和labelInValue配合,默认情况下 onChange 里只能拿到 value,如果需要拿到选中的节点文本 label,可以使用 labelInValue 属性,这个人物搜索组件的Option的children是ReactNode,所以我们需要通过optionLabelProp拿到需要的文本,回显在input框中,同时给后端传递所需要的map结构。

filterOption是否根据输入项进行筛选,如果这个select的option是通过用户输入关键字请求接口渲染的,那么需要设置成false,否则可以通过特定函数设定内部筛选规则,具体的使用方法在第二个例子中具体说明。

单值内部搜索
screenshot.png

<Select className='select-feature'
              showSearch
              filterOption={(input, option) => {
                return (input === option.props.value || option.props.name.indexOf(input)>-1)
              }}
              value={props.id+''}
              onChange={this.handleChange}
            >
              {this.featureOptions}
 </Select>

showSearch 用于在选择框中显示搜索框

filterOption 在这里定义内部搜索逻辑,默认是通过option的value进行匹配,这里为了能既能够通过id也能够通过name进行搜索,通过这个函数进行了特殊设置。

使用Fetch进行接口调用

import {fetchGet, fetchPost, fetchJsonp} from '@ali/uniform-react-components/lib/UniFetch/index';
//大cms后台的post请求需要增加token校验 
const _tb_token_ = window._tb_token_;
const params = {
  //fetch 请求默认是不带 cookie 的
  credentials: 'include',
  //是否允许跨域
  //mode: "no-cors",
  headers: {
  //服务端通过识别X-Requested-With来判定发送的fetch请求是ajax请求,数据统一封装成Json返回
    "X-Requested-With":"XMLHttpRequest"
  },
}
class IO {
  /** * get 请求例子 */
  static fetchGetSample(data) {
    return fetchGet('/video/v5video/item/search.htm?', data,params);
  }

  /** * post 请求例子 */
  static fetchPostSample(data) {
    data._tb_token_ = _tb_token_;
    return fetchPost('/video/v5video/item/add.htm', data,params);
  }
  /** * jsonp 请求例子 */
  static fetchJsonpSample(tags) {
    return fetchJsonp('/common/jsonp/getTagName.htm?', {tags: tags},params);
  }
}

const data = {key1:value1,key2:value2}
IO.fetchPostSample({data})
.then(response=>{})
.catch(err=>{})

其他需要注意的组件

Tabs

注意如果两个tab有数据耦合,需要在切换时有针对性的刷新,比如将标签页面和标签维度放一个tabs中,如果在标签维度中添加了数据,那么切换回标签页面时,标签维度的select选项必须同步,最直接的做法就是刷新页面。
Button htmlType='submit’最常用
InputNumber 利用formatter和parser可以限制InputNumber的输入格式,比如限制用户只能输入一位小数
Spin 模拟loading状态

其它

使用diamond进行前后端分离和环境区分
目前采用diamond进行页面级别的前后端分离,工作流为:

  1. 后端提供接口和预埋数据,后台发布与前端发布隔离,这里的预埋数据前端可以通过window.paramName的全局方式获取;
  2. 后端提供日常,预发和线上三个环境的diamond地址,diamond中加入
    用于前端react渲染;
  3. 前端git发版本,手动在三个diamond环境内添加css和js资源,更新版本号;
  4. 由于不同的子后台域名不同,使用其他子后台接口时需要利用diamond区分接口环境,例如在优酷选品后台中要使用cms后台节目搜索接口,
    在日常的diamond中设置
    window.PROGRAM_SEARCH_URL = ‘//haibao.alibaba.net/youku/api/filter/show.json’;
    在预发和线上则改成
    window.PROGRAM_SEARCH_URL = ‘//haibao.alibaba.com/youku/api/filter/show.json’;前端通过window.PROGRAM_SEARCH_URL获得真实的接口地址。
  5. 存在的问题:diamond方案虽然可以使版本升级通过推送提高效率,但会产生前后端无法同时生效、回滚异常等副作用,需要进一步思考。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/163007.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二、总线控制

文章目录一、引子二、总线判优控制1.基本概念2.方式&#xff08;1&#xff09;集中式①链式查询方式②计数器定时查询方式③独立请求方式&#xff08;2&#xff09;分布式三、总线通信控制1.基本概念2.方式&#xff08;1&#xff09;同步通信①介绍②同步式数据输入③同步数据输…

数据结构与算法学习推荐

推荐&#xff1a;官网地址&#xff1a;http://localhost:8000/algorithm/github&#xff1a;https://github.com/paiDaXing-web/You-Dont-Know-Algorithm 点star 大话搜索搜索一般指在有限的状态空间中进行枚举&#xff0c;通过穷尽所有的可能来找到符合条件的解或者解的个数。…

佳能C5235彩色激光复印机复印有底灰

故障描述&#xff1a; 佳能C5235彩色激光复印机&#xff0c;复印的时候有不同颜色的底灰问题&#xff1b; 检测分析&#xff1a; 打印不同纯色的纸张进行测试发现每张纸的上面都有不同颜色的底灰&#xff1b; 拆机进行检测吧&#xff0c;先打开前盖&#xff0c;拧下左右两边的螺…

CMake基础教程

CMake最大优势是跨平台&#xff0c;可以根据不同的平台生成Makefile文件&#xff0c;看下CMake的基础使用。 cmake&#xff08;单目录单文件&#xff09; 第一个最简单的cmake构建。 demo1.cpp代码&#xff1a; #include <iostream>using namespace std;int main(int…

【基于机械臂触觉伺服的物体操控研究】UR5e动力学建模及代码实现

我的毕设题目定为《基于机械臂触觉伺服的物体操控研究》&#xff0c;这个系列主要用于记录做毕设的过程。 前言&#xff1a;UR系列是优傲公司的代表产品&#xff0c;也是目前比较通用的产品级机械臂。所以我打算用该机械臂进行毕设的仿真实现。关于其动力学建模&#xff0c;网…

台阶问题-

台阶问题 题目描述 有NNN级的台阶&#xff0c;你一开始在底部&#xff0c;每次可以向上迈最多KKK级台阶&#xff08;最少111级&#xff09;&#xff0c;问到达第NNN级台阶有多少种不同方式。 输入格式 两个正整数N&#xff0c;K。 输出格式 一个正整数&#xff0c;为不同…

JVM(一)——架构基础

JVM java虚拟机 java gc 主要回收的是 方法区 和 堆中的内容&#xff0c;以下架构图是重点&#xff1a; 方法区和堆是线程共享&#xff0c;java栈、本机方法栈、程序计数器是线程私有。 运行时数据区可以用Runtime.getRuntime()获取 字节码执行引擎&#xff0c;修改程序计数器…

不要怀疑了,个人也是可以做好跨境电商的!

近几年随着跨境电商卖家们赚得盆满钵满&#xff0c;许多人都想从中分一杯羹&#xff0c;进而入住了跨境电商市场&#xff0c;有人与一些公司企业合作&#xff0c;也有人选择了自己做跨境电商平台&#xff0c;个人做的优劣势又有哪些呢&#xff1f; 个人做跨境电商平台最明显突…

A V L树

概念 在之前介绍了搜索二叉树&#xff0c;但是当我们插入的数据若是有序或者接近于有序&#xff0c;那么此时查找的效率底下&#xff0c;于是俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法&#xff1a;当向二叉搜索树中插入新结点后&am…

javaEE学生教学实习计划申报系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 javaEE学生教学实习计划申报系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql&…

正点原子【第四期】手把手教你学 Linux之驱动开发篇-01

学习目的 了解驱动开发和应用开发的过程&#xff0c;具有一定的基础就行 第一讲&#xff1a;linux驱动开发与裸机开发区别 刚开始听不懂很正常&#xff0c;等之后学了一点你就会知道它说啥了 第二讲&#xff1a;字符设备驱动开发基础 字符设备驱动是最简单的&#xff0c;块设…

C++ 移动语义

从拷贝说起我们知道&#xff0c;C中有拷贝构造函数和拷贝赋值运算符。那既然是拷贝&#xff0c;听上去就是开销很大的操作。没错&#xff0c;所谓拷贝&#xff0c;就是申请一块新的内存空间&#xff0c;然后将数据复制到新的内存空间中。如果一个对象中都是一些基本类型的数据的…

【Unity3D】绘制物体外框线条盒子

1 需求描述 点选物体、框选物体、绘制外边框 中介绍了物体投影到屏幕上的二维外框绘制方法&#xff0c;本文将介绍物体外框线条盒子绘制方法。 内框&#xff1a;选中物体后&#xff0c;绘制物体的内框&#xff08;紧贴物体、并与物体姿态一致的内框盒子&#xff09;外框&#…

Python与C++语法比较--字符串篇

tags: C Python 写在前面 刷lc从Python转向C, 不只是语法层面, 还要改变很多的API, 这次记录一下C和Python在字符串方面的一些区别, 供参考. 基本区别 Python字符串是不可变类型, 而C的String为容器(本质上是一个类的别名, 说容器有点不合适, 因为容器内的元素类型已经被指…

Kotlin中的Lambda编程

文章目录1.集合的创建与遍历2.集合的函数式API3.Java函数式API的使用1.集合的创建与遍历 传统意义上的集合主要是List和Set&#xff0c;再广泛一点的话&#xff0c;像Map这样的键值对数据结构也可以包含进来。List&#xff0c;Set和Map再Java中都是接口&#xff0c;List主要的…

Java设计模式-命令模式Command

介绍 命令模式&#xff08;Command Pattern&#xff09;&#xff1a;在软件设计中&#xff0c;我们经常需要向某些对象发送请求&#xff0c;但是并不知道请求的接收 者是谁&#xff0c;也不知道被请求的操作是哪个&#xff0c; 我们只需在程序运行时指定具体的请求接收者即可&…

数影周报:TikTok因在线跟踪被罚500万欧,Windows 7退出历史舞台

本周看点&#xff1a;TikTok因在线跟踪被法国罚款500万欧元 &#xff1b;思科已裁员近700 人&#xff1b;Windows 7退出历史舞台&#xff1b;亚马逊向所有卖家开放Buy with Prime服务&#xff1b;“全路程”完成2亿元C轮融资......数据安全那些事TikTok因在线跟踪被法国罚款500…

Android13 wifi无线调试adb连接设置

在进行adb调试的时候&#xff0c;有时候需要使用wifi连接&#xff0c;或者wifi连接较为方便&#xff0c;早些的Android上&#xff0c;需要设置端口等操作&#xff0c;adb tcpip 6666参考android wifi adb 调试 - 简书 (jianshu.com)好几步操作&#xff0c;在Android13上&#x…

Deque 的理解 STL中stack与queue为什么选择使用deque为底层模板容器

目录 一、Deque的引入 二、Deque是什么&#xff1f; 三、deque的遍历方式&#xff1f;deque的缺陷&#xff1f; 四、它为什么能更贴合与stack与queue&#xff1f; 五、STL中vector与list的底层实现 一、Deque的引入 Stack、Queue在之前的博客中我也是分别使用了更容易处理…

【蓝桥杯】历届真题 杨辉三角形 (省赛)Java

【问题描述】 下面的图形是著名的杨辉三角形: 如果我们按从上到下、从左到右的顺序把所有数排成一列&#xff0c;可以得到如下数列: 1,1&#xff0c;1&#xff0c;1&#xff0c;2,1&#xff0c;1&#xff0c;3,3&#xff0c;1&#xff0c;1,4&#xff0c;6,4&#xff0c;1&…