最近公司做了一个系统,因为页面涉及的表单交互非常多,如果使用之前的 Node + Express 的开发模式效率是非常低的,因此经过考虑,最后决定使用 Node + React 的开发模式,并且使用了蚂蚁金服出品的开源框架 Ant Design。

正如Ant Design 官方介绍: "在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,给设计师和工程师带来很多困扰和重复建设,大大降低了产品的研发效率。"在这次开发的项目中,因为数据交互非常频繁,大量的表单、时间选择器、表格、单选多选框,以及各种标识状态的组件,如果光靠手写或者使用 jQuery 插件,其开发的工作量仍然是相当大的,因此,Ant Design "经过大量的项目实践和总结,沉淀出一个中台设计语言 Ant Design。旨在统一中台项目的前端 UI 设计,屏蔽不必要的设计差异和实现成本,解放设计和前端的研发资源。"

同时,React 也是第一次使用,起初对于这种 Html 与 JS 代码混杂的书写格式搞得很不舒服,因为作为一个前端开发者,被"结构与逻辑分离"的思想洗脑太久了,但实际上组件的 HTML 是组成一个组件不可分割的一部分,能够将 HTML 封装起来才是组件的完全体,React 发明了 JSX 让 JS 支持嵌入 HTML 不得不说是一种非常聪明的做法,让前端实现真正意义上的组件化成为了可能。所以在使用了 React 开发一段时间后,越来越感觉到 React 封装组件的高效。而 Ant Design 则封装了一系列高质量的 React 组件,十分适用于在企业级的应用中,框架提供的 api 十分详尽,上手和使用相对简单,值得一提的是, Ant Design 使用 ES6 进行编写,因此使用过程中对 ES6 也是一次学习的机会。

在这里主要就项目中使用到的主要的组件以及遇到的一些坑进行总结,也是对这个项目开发的一个简单的梳理。

项目开发中主要用到的组件:

Button、Icon、Row/Col、BackTop、Pagination、Tabs、Checkbox、Cascader、Form、Rate、Select 、Modal、Message、Table

Button 的使用比较简单,需要注意的地方是为了和原生 button 进行区分,Form表单中的 Button 组件的submit 需要写成 htmlType = "submit" ,其他类似的组件也是同理。

举例:

使用了两种类型的Button, 并且定义了 Button 的点击事件,事件在 render() 方法外进行定义。

Icon的使用非常简单,Ant Design 提供了常用了Icon , 使用时只需要点击图标即可完成代码的复制。Icon 自带两个属性,type 定义了图标的类型, spin 定义图标是否有旋转动画。

Row / Col 主要用于栅格布局,和BootStrap 的使用十分相似,不同的是 Ant Design 默认把页面分成24份,而不是12份,增加了布局的灵活度。

Tabs 十分实用,通过Tabs 的切换可以十分高效地在同一个页面中展现不同业务的信息。Tabs 的使用也十分简单,只要将每一个 Tab 面板放在 Tabpane 标签里面即可。值得一提的是,如果要实现标签的动态切换(根据 state 的状态进行切换),需要在 Tabs 标签中添加 activeKey 属性,别且绑定 到具体的控制标签切换的 state 上,更重要的是,需要添加 onChange 方法,在标签切换的事件中设置当前 tab 的 state,如下:

Form 是项目中用的最多的表单了,表单项通过 FormItem 进行定义,并且可以设置对其方式、验证规则、错误提示信息以及绑定初始值,十分有用。

在最外层的 Form 标签上定义了表单的提交方法,并且把所有的表单项都获取复制到 values 参数中,因此可以对 values 对象进行操作,获取到对象的字段值并经行处理,如下:

Modal 主要在弹框和提示框中使用,如果弹框中需要进行数据操作,如选择和填写信息,则直接使用 Modal ,定义标题,按钮方法,以及弹框中的具体内容;如果只是简单的信息提示,比如成功或失败、警告等,则可以根据场景使用 Modal 下的 success、warning、confirm、info方法,使用起来也十分方便,需要注意的是,在这些方法中无法获取到正确的 this 指向,因此需要在方法外部先获取到 this 指针。如下:

Table 的的使用过中则遇到了很多的坑,主要是因为表格中的数据都是通过请求接口获取到的,因此需要对数据进行动态渲染,同时表格中的数据还允许操作,甚至,有多个表格需要同时渲染,因此表格的一切都要再请求接口后动态生成,然后渲染到 DOM 结构中去。举例:

在这里表格中的数据通过请求接口获取,每一个 item 包含了表格中的所有数据,同时手动为表格中的每一行数据添加一个 index 属性用于标识数据的唯一性(所有通过 for 或者 map 循环出来的数据都需要加标识条目唯一性的 key 值,可以是 id,也可以是自己添加的属性,唯一即可,不这样做的话浏览器会报出警告)。

当获取到数据并生成所有的表格结构后,将此对象复制给 state,并插入到 DOM,便可以实现动态表格以及动态数据的插入。表格的使用,谨慎仔细是十分重要的。

Cascader 在封装选择省市区组件中使用到,这里也有较多的技巧。组件代码如下:

 import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import Cascader from 'antd/lib/cascader'
import Button from 'antd/lib/button'
import message from 'antd/lib/message'
import ajax from '../../utils/service'
import * as inputActions from '../../actions/input' let province = [
{ value: 2, label: "北京", isLeaf: false },
{ value: 3, label: "安徽", isLeaf: false },
{ value: 4, label: "福建", isLeaf: false },
{ value: 5, label: "甘肃", isLeaf: false },
{ value: 6, label: "广东", isLeaf: false },
{ value: 7, label: "广西", isLeaf: false },
{ value: 8, label: "贵州", isLeaf: false },
{ value: 9, label: "海南", isLeaf: false },
{ value: 10, label: "河北", isLeaf: false },
{ value: 11, label: "河南", isLeaf: false },
{ value: 12, label: "黑龙江", isLeaf: false },
{ value: 13, label: "湖北", isLeaf: false },
{ value: 14, label: "湖南", isLeaf: false },
{ value: 15, label: "吉林", isLeaf: false },
{ value: 16, label: "江苏", isLeaf: false },
{ value: 17, label: "江西", isLeaf: false },
{ value: 18, label: "辽宁", isLeaf: false },
{ value: 19, label: "内蒙古", isLeaf: false },
{ value: 20, label: "宁夏", isLeaf: false },
{ value: 21, label: "青海", isLeaf: false },
{ value: 22, label: "山东", isLeaf: false },
{ value: 23, label: "山西", isLeaf: false },
{ value: 24, label: "陕西", isLeaf: false },
{ value: 25, label: "上海", isLeaf: false },
{ value: 26, label: "四川", isLeaf: false },
{ value: 27, label: "天津", isLeaf: false },
{ value: 28, label: "西藏", isLeaf: false },
{ value: 29, label: "新疆", isLeaf: false },
{ value: 30, label: "云南", isLeaf: false },
{ value: 31, label: "浙江", isLeaf: false },
{ value: 32, label: "重庆", isLeaf: false },
{ value: 33, label: "香港", isLeaf: false },
{ value: 34, label: "澳门", isLeaf: false },
{ value: 35, label: "台湾", isLeaf: false }
]; let options = province class Location extends Component {
constructor(props) {
super(props); }
state = {
options: options,
inputValue: '',
} componentWillMount(){
const {hideLoading} = this.props;
setTimeout(() => { hideLoading()}, 1000)
} _onChange = (value, selectedOptions) => {
console.log(value);
this.setState({
inputValue: selectedOptions.map(o=>o.label).join(', ')
});
const onChange = this.props.onChange; if (onChange) {
onChange({...value});
}
} _loadData = (selectedOptions) => {
const targetOption = selectedOptions[selectedOptions.length - 1];
const id = targetOption.value;
targetOption.loading = true; if (selectedOptions.length == '1') {
// 点击省,获取市
ajax.post(ajax.api.GETSERVICEAREA, { id: id, token: localStorage.token }).then(data => {
if(data.status.code == '1'){
targetOption.loading = false;
targetOption.children = [];
data.result.map((v, k)=>{
// 拼出市
targetOption.children.push({
value: v.id,
label: v.name,
isLeaf: false,
});
});
this.setState({
options: [...this.state.options],
});
}
});
}else if (selectedOptions.length == '2') {
// 点击市,获取区
ajax.post(ajax.api.GETSERVICEAREA, { id: id, token: localStorage.token }).then(data => {
if(data.status.code == '1'){
targetOption.loading = false;
targetOption.children = [];
data.result.map((v, k)=>{
// 拼出区
targetOption.children.push({
value: v.id,
label: v.name,
isLeaf: true,
});
});
this.setState({
options: [...this.state.options],
});
}
});
}else {
targetOption.loading = false;
}
} _resetLocation = () => {
document.getElementsByClassName('ant-cascader-picker-clear')[0].click();
this.setState({
inputValue: '',
});
} render() {
return (
<div>
<Cascader
options={this.state.options}
loadData={this._loadData}
onChange={this._onChange}
changeOnSelect
placeholder=""
/>
</div>
)
}
} export default connect(state => ({
showLoginLayer: state.login.isShowLoginLayer
}), inputActions)(Location)

其中要注意的地方很多,首先是初始值的设置。因为使用省市区组件,不能一次性拉取到所有的地区,这样会十分消耗性能,造成不良的用户体验,正确的做法是在点击时获取下一级的地区信息,这样有针对性的请求可以减少加载时间,那么问题来了,如何实现?

首先,使用 Cascader 的 api 中有 loadData 属性,可以定义数据的加载,同时,onChange 事件可以监听到每一次的数据变化,但是使用 Cascader 有一个限制,便是第一级的数据需要在加载组件之前就定义并获取到,否则无法进行下一级数据的加载,因此这里单独定义了所有了省的数据:

onChange 事件获取到当前选择的对象,并提供了两个参数,分别是选择的当前值(数组类型)和选择的多级对象(当前选择的对象和当前对象下一级的数组对象)。

在获取到当前选中的对象后对值进行拼接处理并赋值给 inputValue (在组件框中显示的选中值),同时设置onChange()方法,将值的变化情况通知给父组件(如 FormItem )

loadData()方法用于组件级联数据的加载,其参数就是 onChange()方法的第二个参数,在这里获取到参数的最后一个对象(即当前点击的对象),通过判断参数的长度来识别当前要获取的数据的类型(市还是区),获取到数据后生成组件要求的数据格式,最后将格式化的数据赋值给 option 就可以了。

最后,模拟了一个重置(清空)的功能,Cascader 值的清空有两点,一是选择框内容的清空,二是级联数据的重置,内容的清空比较简单,直接将 inputValue 设置为空即可,而级联数据的重置不能将 option 设置为空,这样会导致级联组件无法使用(下拉数据为空),为此使用了一个小技巧:

在组件的 api 属性中有一个allowClear 属性,默认是 true,即允许清空,其效果是当鼠标移到选择数据后的级联表单上会出现一个 叉号的按钮,如下:

通过开发者工具可以获取到这个按钮的类名,那么之后的操作就简单了: 自定义一个重置(清空)按钮,然后触发清空按钮的事件即可:

以上是一些常用组件使用过程中需要注意的地方,针对 react 和 ant design 使用过程中出现的问题和解决方案,请参考文章:React 开发常见报错解决方法

Ant Design 使用小结的更多相关文章

  1. 阿里开源项目之Ant Design Pro

    本篇文章主要包含的内容有三个方面. 第一.Ant Design Pro简介; 第二.Ant Design Pro能做什么; 第三.初步使用; 我相信通过这三个方面的讲解能让你大概知道Ant Desig ...

  2. Puppet Openstack Mitaka Design Summit小结

    Puppet Openstack Design Summit小结 经过Puppet Openstack社区的不断努力,Puppet Openstack社区目前提供的Official Modules已经 ...

  3. Ant Design 的一个练习小Demo

    Ant Design 由蚂蚁金服团队出品, 基于 React 的组件化开发模式,封装了一套丰富而实用的 UI 组件库. 在这个练习Demo 中,按照 Ant Design 官网的教程示例,尝试使用 A ...

  4. 实现Ant Design 自定义表单组件

    Ant Design 组件提供了Input,InputNumber,Radio,Select,uplod等表单组件,但实际开发中这是不能满足需求,同时我们希望可以继续使用Form提供的验证和提示等方法 ...

  5. Ant Design UI组件

    Ant Design 是面向中台的 UI 设计语言.  http://ant.design/

  6. Ant Design Pro+Electron+electron-builder实现React应用脱离浏览器,桌面安装运行

    ant-design-pro ----> version :2.3.1 由于网上Ant Design Pro+Electron的资料太少,我就贡献一点经验   最近需要讲AntD Pro项目(以 ...

  7. button样式篇一(ant Design React)

    这篇来介绍button中elementUi.iview.ant中样式结构 ant Design react ant-react中button分两个文件less: mixins.less:根据butto ...

  8. elementUi、iview、ant Design源码button结构篇

    在看elementUI的button组件的时候,一起和iview.ant Design的button组件比 较功能.样式.代码结构,看他们的一些不同点,不同的写法哪种会好些,button的对外开放的功 ...

  9. 使用selenium操作ant design前端的页面,感觉页面没加载完

    因需要收集页面数据,遂准备使用selenium爬取瓦斯阅读页面, 瓦斯网站使用的是ant design,元素定位非常困难,页面元素都没有ID,现在还只是能做到操作登录,不能自动打开订阅,查询某公众号, ...

随机推荐

  1. Linq中dbSet 的查询

    1.Find:按照关键字的ID号来查询(速度快) 如: ADShiTi aDShiTi = db.ADShiTis.Find(id); 2.FirstOrDefault:根据部分条件查询,显示最前的一 ...

  2. 微信H5支付 在其他浏览器调用微信支付

    微信H5支付的相关资料不是很多.不过步骤上来说不是很复杂 比公众号支付简单很多. 先上官方文档吧 https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapt ...

  3. jdk带的一些工具,强悍

    这些工具有的已经接触到了,功能很强悍,但是使用也有点复杂(参数) 在代码中使用System.setProperty()或者在启动程序时使用-D选项设置代理服务器地址和端口 看看别人的研究: JDK自带 ...

  4. vue2.0 $emit $on组件通信

    在vue1.0中父子组件通信使用$dispatch 和 $broadcast,但是在vue2.0中$dispatch 和 $broadcast 已经被弃用. 因为基于组件树结构的事件流方式实在是让人难 ...

  5. ibdata1文件损坏时恢复InnoDB单表测试

      Preface       ibdata1 file is a shared system tablespace of innodb engine.Although we always set v ...

  6. 每天一个Linux命令(14):dpkg命令

    dpkg命令是Debian Linux系统用来安装.创建和管理软件包的实用工具. 语法: dpkg (选项) (参数) 选项: -i:安装软件包: -r:删除软件包: -P:删除软件包的同时删除其配置 ...

  7. C计算了一下

    #include <stdio.h> int main(){ int a,b,c,e; a=6 + 5 / 4 - 2; b=2 + 2 * (2 * 2 - 2) % 2 / 3; c= ...

  8. Django数据模型--字段整理

    一.字段 1.CharField: 字段数据类型为字符串 2.IntegerField: 字段数据类型为整形 3.BooleanField: 布尔类型 4.NullBooleanField: 允许为空 ...

  9. python 学习总结----正则表达式

    正则表达式 应用场景 - 特定规律字符串的查找,切割,替换 - 邮箱格式:URl,IP地址等的校验 - 爬虫项目中,特定内容的提取 使用原则 - 只要使用字符串等函数能解决的问题,就不要使用正则 - ...

  10. Win7/8, convert dynamic disk volume to basic volume.

    之前不小心用了Win8自带的Disk Management 来调整磁盘分区的大小,当时跳出来一个warning窗口,说如果继续操作会变成dynamic disk,然后xxxx. 我心想都是Window ...