前端004/React常用UI组件
每天进步一点点〜
Ant Design of React //蚂蚁金服设计平台。需要应用何种类型组件可参考API
React + mobx + nornj 开发模式文件说明:
【1】。A.t.html (.html / .scss / .js / 文件包路径:src/web/pages)
-->html代码 (页面设计,各种标签。标签有哪些属性及用法参考“Ant Design of React”) /
【2】。A.m.scss
-->样式 (页面显示样式统一管理) /
【3】。A.js
--> javascript代码,事件操作。 /
【4】。AStore.js (src/stores/pages包下面)
-->路由页面 (用于与后端交互,获取数据,并将数据返回给A.js,render渲染到页面)/
(一)。Modal对话框:
项目需求:注册一个用户,当用户点击“注册”按钮时,会将之前注册的数据替换掉。因此,需要提示两次,以警示用户“确定要注册!”
该代码实现:较验文本数据必填 & 正则 | 比较密码输入是否一致 | 弹出提示框
实现代码/html :
1 <!--注册用户--> 2 <template name="registUser"> 3 <ant-Modal width={668} visible="{certificateregistList.showRegistUser}" footer={null} onCancel={onAddModalCancel}> 4 <ant-Tabs> 5 <ant-TabPane tab="注册用户" /> 6 </ant-Tabs> 7 <fj-Row class="{styles.btn}"> 8 <fj-Col offset="2" l="8" > 9 <ant-Form onSubmit={handleRegister}> 10 <ant-FormItem label="用户名" {...formItemParams()}> 11 <#userID> 12 <ant-input class="{styles.input}" placeholder="请输入用户名!"/> 13 </#userID> 14 </ant-FormItem> 15 <ant-FormItem label="密码" {...formItemParams()}> 16 <#userPwd> 17 <ant-input type="password" class="{styles.input}" placeholder="请输入用户密码!"/> 18 </#userPwd> 19 </ant-FormItem> 20 <ant-FormItem label="确认密码" {...formItemParams()}> 21 <#userConfirmPwd> 22 <ant-input type="password" class="{styles.input}" placeholder="请再次输入密码!"/> 23 </#userConfirmPwd> 24 </ant-FormItem> 25 <ant-FormItem label="最大次数" {...formItemParams()}> 26 <#maxNum> 27 <ant-input class="{styles.input}" placeholder="可以重复申请的最大次数!"/> 28 </#maxNum> 29 </ant-FormItem> 30 <div class="{styles.deploy_button}"> 31 <ant-Button style="margin-left:168px;" type="primary" class="btn" htmlType="submit" disabled="{certificateregistList.showRegistBtn}">注册</ant-Button> 32 </div> 33 </ant-Form> 34 </fj-Col> 35 </fj-Row> 36 </ant-Modal> 37 </template>
实现代码/js :
1 //注册用户 2 @registerTmpl('RegistUser') 3 @inject('store') 4 @Form.create() 5 @observer 6 export class RegistUser extends Component{ 7 // 用户名 8 userID(options) { 9 return this.props.form.getFieldDecorator('userID', { 10 rules: [{ required: true, message: '请填写用户名!' }], 11 })(options.result()); 12 } 13 14 // 用户密码 15 userPwd(options) { 16 return this.props.form.getFieldDecorator('userPwd', { 17 rules: [{ required: true, message: '请填写用户密码!' }, 18 {pattern:/^[a-zA-Z]\w{5,19}$/,message: '密码只能以字母开头,长度在6~20,只能包含字母、数字和下划线!' },], 19 })(options.result()); 20 } 21 22 // 重复用户密码 23 userConfirmPwd(options) { 24 return this.props.form.getFieldDecorator('userConfirmPwd', { 25 rules: [{ required: true, message: '请确认用户密码!' }, 26 {pattern:/^[a-zA-Z]\w{5,19}$/,message: '密码只能以字母开头,长度在6~20,只能包含字母、数字和下划线!' }, 27 {validator: this.verifyPassword,}], 28 })(options.result()); 29 } 30 31 //重复申请证书的最大次数 32 maxNum(options){ 33 return this.props.form.getFieldDecorator('maxNum', { 34 rules: [{ required: true, message: '请填写申请证书最大次数!' }, 35 {pattern:/^([1-9]|10)$/,message: '请输入>0且<=10的正整数数字!' }], 36 })(options.result()); 37 } 38 39 //较验两次输入密码是否一致 40 verifyPassword = (rule, value, callback) => { 41 const form = this.props.form; 42 if (value && value !== form.getFieldValue('userPwd')) { 43 callback('两次输入密码不一致!'); 44 } else { 45 callback(); 46 } 47 } 48 49 //取消【遮罩】 50 @autobind 51 onAddModalCancel() { 52 this.props.store.certificateregistList.setShowRegistUser(false); 53 } 54 55 //注册提交 56 @autobind 57 handleRegister(e){ 58 const { store: { certificateregistList } } = this.props; 59 e.preventDefault(); //阻止未填项 60 this.props.form.validateFields((err, values) => { 61 if (!err) { 62 var attrs=[{ 63 "Name":"hf.Revoker", 64 "Value":"true", 65 }] 66 67 let param={ 68 "ID": values.userID, 69 "Type": "user", //用户类型,要求固定值为user 70 } 71 72 //弹出框警告提示 73 Modal.confirm({ 74 title: '注册后,已有用户将会被覆盖!!!', 75 content: '', 76 onOk() { //确认后再提示。。 77 Modal.confirm({ 78 title: '确认注册新用户!!!', 79 content: '已有用户将会被覆盖...', 80 onOk() { //确认后注册 81 const closeLoading = Message.loading('正在保存数据...', 0); 82 certificateregistList.setShowRegistBtn(true); //控制注册按钮显示 83 Promise.all([ 84 certificateregistList.getRegister(param), //注册用户 85 ]).then(()=> { 86 certificateregistList.setShowRegistBtn(false); 87 closeLoading(); 88 }); 89 }, 90 onCancel() {}, 91 }); 92 }, 93 onCancel() {}, 94 }); 95 } 96 }); 97 } 98 99 render() { 100 const { store: { certificateregistList } } = this.props; 101 return tmpls.registUser(this.props, this, { 102 styles, 103 certificateregistList, 104 }); 105 } 106 }
(二)。Tag标签:
业务需求:数据动态加载,每行后追加一个Tag标签,点击Tag标签后,对应显示文本框,可以录入值并将值进行显示。。。
效果:
代码如下所示:
【1】。html
1 <template name="storageExpand"> 2 <ant-Form onSubmit={handleSubmit} layout="vertical"> 3 <p><b>存储名称:</b>{xx.xx.name}</p> 4 <#each {{nodeList}}> 5 <p> 6 <b>Node{{@index | +(1)}}:</b><br/> 7 <#each {{xx}}> 8 {{this}}, 9 </#each> 10 </b> IP: 11 <#each {{xx}}> 12 {{this}}, 13 </#each> 14 </b> 设备: 15 <#each {{xx}}> 16 {{this}}, 17 </#each> 18 19 <!--tag标签值--> 20 <#each {{tags}}> 21 <#if {{isLongTag}}> 22 <ant-Tooltip title={@item} key={@item}> 23 {tagItem(@item,@index)} 24 </ant-Tooltip> 25 <#else> 26 {tagItem(@item,@index)} 27 </#else> 28 </#if> 29 </#each> 30 31 <!--控制显示tag标签还是文本框,初始显示tag标签--> 32 <#if {{inputVisible}}> 33 {inputItem(@index)} 34 <#else> 35 {addItem(@index)} 36 </#else> 37 </#if> 38 </p> 39 </#each> 40 <p><b>存储:</b>{xx || "空"}</p> 41 <p><b>Master:</b>{{xx ? ('是', '否') }}</p> 42 <div class="{styles.btnArea}"> 43 <ant-Button class="{styles.btn}" type="primary" htmlType="submit" disabled="{showExpand}">扩容</ant-Button> 44 </div> 45 </ant-Form> 46 </template>
【2】。js
1 import React, { Component } from 'react'; 2 import { findDOMNode } from 'react-dom'; 3 import { observable, computed, toJS } from 'mobx'; 4 import { observer, inject } from 'mobx-react'; 5 import nj from 'nornj'; 6 import { registerTmpl } from 'nornj-react'; 7 import { autobind } from 'core-decorators'; 8 import Input from 'flarej/lib/components/antd/input'; 9 import Icon from 'flarej/lib/components/antd/icon'; 10 import Tag from 'flarej/lib/components/antd/tag'; 11 import Message from 'flarej/lib/components/antd/message'; 12 import Form from 'flarej/lib/components/antd/form'; 13 import Notification from '../../../utils/notification'; 14 import styles from './storageManager.m.scss'; 15 import tmpls from './storageManager.t.html'; 16 17 //存储扩容功能 18 @registerTmpl('StorageExpand') 19 @inject('store') 20 @Form.create() 21 @observer 22 export default class StorageExpand extends Component{ 23 @observable nodeList=[]; //获取设备信息,组成新数组对象。 24 @observable obj = { 25 inputVisible: false, 26 tags: [], 27 } 28 @observable inputVisible=false; //控制显示tag标签 OR 文本框 29 @observable inputValue=''; //文本框输入值 30 @observable isLongTag = false; //是否是长字符,控制是否显示Tooltip 31 @observable showExpand=false; //控制显示【扩容】按钮 32 33 componentWillMount() { 34 const { store: { storageManager } } = this.props; 35 this.nodeList = storageManager && storageManager.xx && storageManager.xx.xx; 36 this.nodeList = this.nodeList.map((value, key)=>{ 37 return value = {...value, ...this.obj}; 38 }); 39 } 40 41 componentDidUpdate() { 42 43 } 44 45 //当inputVisible=false时,显示tag标签.(即初始进入显示tag标签) 46 addItem = (index) => ( 47 <Tag 48 onClick={()=>this.showInput(index)}><Icon type="plus" />添加 49 </Tag> 50 ) 51 52 //点击tag标签,添加时,显示文本框。 53 showInput = (index) => { 54 this.nodeList[index].inputVisible=true; 55 } 56 57 //点击tag标签,显示文本框供用户录入数据 58 inputItem = (index) => ( 59 <Input 60 type="text" 61 size="small" 62 style={{"width": 78}} 63 value={this.inputValue} 64 onChange={this.handleInputChange} 65 onBlur={()=>this.handleInputConfirm(index)} 66 onPressEnter={()=>this.handleInputConfirm(index)} 67 /> 68 ) 69 70 handleInputChange = (e) => { 71 this.inputValue=e.target.value; 72 this.isLongTag = this.inputValue.length >= 20 ? true : false; 73 } 74 75 handleInputConfirm = (index) => { 76 const inputValues = this.inputValue; 77 let newTags = this.nodeList[index].tags ? [...this.nodeList[index].tags] : [] 78 if (inputValues && newTags.indexOf(inputValues) === -1) { 79 newTags = [...newTags, inputValues]; 80 } 81 this.nodeList[index].tags=newTags; 82 this.inputValue=''; 83 this.nodeList[index].inputVisible=false; 84 } 85 86 //文本框失去焦点后,将值赋给tag标签,用于在页面显示。 87 tagItem = (tag, index) => { 88 return ( 89 <Tag 90 key = {tag} 91 closable = {index !== -1} 92 afterClose = {() => this.handleClose(tag, index)} 93 > 94 {this.isLongTag ? `${tag.slice(0, 20)}...` : tag} 95 </Tag> 96 ) 97 }; 98 99 100 //移出添加的标签内容 101 handleClose = (removedTag, index) => { 102 const newTags = this.nodeList[index].tags.filter(tag => tag !== removedTag); 103 this.nodeList[index].tags=newTags; 104 } 105 106 //扩容触发事件 107 @autobind 108 handleSubmit(e){ 109 const { store: { storageManager } } = this.props; 110 e.preventDefault(); 111 var storageContent=[]; 112 this.nodeList.map((value, key)=>{ 113 var option = { 114 "manage":[], 115 "storage":[], 116 "devices":[], 117 "zone": 1 118 }; 119 option.manage.push(this.nodeList[key].manage[0]); //节点名 120 option.storage.push(this.nodeList[key].storage[0]); //IP 121 option.devices.push(this.nodeList[key].devices[0]); 122 for(let i=0;i<this.nodeList[key].tags.length;i++){ 123 option.devices.push(this.nodeList[key].tags[i]); //设备-新添加 124 } 125 storageContent.push(option); 126 }); 127 let param={ 128 "xx":xx 129 }; 130 this.showExpand=true; //控制按钮不可用 131 const closeLoading = Message.loading('正在保存数据...', 0); 132 Promise.all([ 133 storageManager.getSaveStorage(param), //保存数据 134 ]).then(() => { 135 this.showExpand=false; 136 closeLoading(); 137 }); 138 } 139 140 render() { 141 const { store: { storageManager } } = this.props; 142 return tmpls.storageExpand(this.state, this.props, this, { 143 styles, 144 storageManager, 145 }); 146 } 147 }
体胖还需勤跑步,人丑就该多读书!