这块儿经验来自于代码优化
判断条件学会精简
- 判断条件不同结果相同可以使用&&连接
- 判断条件满足其中之一可以使用||
- 能够合并的代码就要合并
// 合并之前
if(a.length > 20 && name === 'name') {
message.error('名称不能超过20字')
} else if(a.length > 20 && name === 'prename') {
message.error('预览名称不能超过20字')
} else { ... }
// 合并之后
if(a.length > 20 && (name === 'name' || name === 'prename' )) {
message.error('名称或者预览名称不能超过20字')
} else { ... }
模块化,组件化思想
- 请求参数和返回数据处理差不多的情况下就要学会合并,譬如:新增和修改可以共用一个方法,req、url和提示语可以根据类型来定义,另外req请求多传参数也不会影响后端处理;
- 发送请求前的数据验证可以单独封装一个函数来处理,可以参考管理员管理模块的新增和修改;
// 在Com组件中
static validWhenAddOrUpdate(state) {
if (!state.userId) {
message.error('账号ID不能为空');
return false
}
if (state.userId.search(' ') !== -1) {
message.error('账号ID不能带有空格(前面,中间,后面都不行)');
return false
}
if (!state.userName) {
message.error('账号姓名不能为空');
return false
}
if (!state.department) {
message.error('所属部门不能为空');
return false
}return false
}
return true;
}
//使用的地调用
handleOkNew = () => {
const thisNewState = this.new.state;
if (!Com.validWhenAddOrUpdate(thisNewState)) {
return;
}
}
- 样式需放到css里面,统一管理
- 合理使用参数,就可以与其他组件公用一个方法
基础知识要过关
- map改变原数组不需要return,如果是使用循环则使用forach或者_.each
- 该单独写的函数需单独写,避免函数中嵌套函数,函数要做到小而细
- 封装的函数注意函数的调用时机
- 变量使用es6的let或者const(常亮使用const定义)
要学会处理异常数据
- 接收数据时先做好可能判断,避免在html中写js代码,否则会因为数据不规范导致页面崩溃(所以可以提前定义变量,html只负责渲染)
- 判断数据最好先设置一个空数据,在对数据进行处理,合理利用三目运算判断,如果判断条件与第一种可能相同可以使用||符号
学会代码简洁,复用、使用扩展运算符等
-
// fixme:可以在config中设置一个初始条件,使用扩展符(...)的方式加载进来,同时方便重置的时候直接使用
-
最开始可以设置一个初始值,把需要传递的req设置到一个对象中
-
getReq = () => { let conditionObj = this.state.conditionObj; let request = { customerTypes: conditionObj.clientType, investDurationType: conditionObj.deadline, netValue: conditionObj.product, openType: conditionObj.openType, productObject: conditionObj.productObject, productTypes: conditionObj.productType, raiseWays: conditionObj.raise, saleDateEnd: conditionObj.saleEndDate, saleDateStart: conditionObj.saleStartDate, specialFieldType: conditionObj.special, startPointType: conditionObj.investment, }; return request; };
-
在需要的地方引入,在可以添加其他键值对
-
在state中存入一个reqObj专门用来最为发请求的对象,以便后面的接口调用
-
之后需要调用可以直接利用es6的扩展运算符进行copy
动态渲染表格数据
this.setState({loading: false});
let cnt = res.content ? res.content : {}, dataSource = [];
let columns = [
{
title: '渲染的时间',
dataIndex: 'date',
width: 200,
align: 'center',
fixed: 'left',
}
];
_.each(cnt.date, (item) => {
dataSource.push({date: item})
});
_.each(cnt.data, (val, key) => {
let column = {
title: key,
dataIndex: key,
width: 140,
align: 'center',
};
if (key === '需要固定的值') {
column.fixed = 'left'
}
// 根据length判断表格宽度
if (key.length > 4) {
column.width = 200
}
// 整理dataSourece,根据后台返回数据返回数据整理,并添加key值
_.each(dataSource, (item, i) => {
item[key] = number(val[i], 2);
item.key = i;
});
columns.push(column);
});
let tableWith = calculate(columns);
if (tableWith < this.state.width - 200) {
_.each(columns, (item, i) => {
delete item.fixed
});
}
this.setState({dataSource, columns, totalModal: cnt.total});
注意熟悉规范,小细节,知识点
// fixme: 代码引入顺序按照 第三方库-公共方法-公共组件-各模块配置;每个 import 以分号结尾;删除未使用的引入
- 数据都要考虑为空,不存在,undefined等情况。特别是使用js中的方法
- 未判断数据,导致toFixed报错(可以用三目或者使用number方法转换)
- 直接取对象数组中的值,可能会存在找不到对应key值而报错
- res中的返回值吗,不能绝对信任,都应加上||判断
- props中传值也需对传递过来要使用的值进行验证,否则直接进行split划分会报错
- map对数据格式要求严格,如果不是数组也会报错(可以使用underscore中的_.map,或者使用判断,或者使用三目不存在就为[])
从别人代码中获取经验
-
自定义数组,遍历展示
-
render: (val) => { let item = _.find(whether, (item) => { return item.value === val }); let text = item ? item.label : ''; return <span>{text}</span> } export const whether = [ {label: '不限', value: ''}, {label: '是', value: '1'}, {label: '否', value: '0'}, ]; // 方法封装直接根据对象数组中的value取出相应label中的值 export const getLabel = (map, v,name= 'label',val='value') => { // 注:Number会将null值转换为0,所以你的值中有0会被错误转换 //const res = _.find(map, item => Number(item[val]) === Number(v)); // 改造之后 const res = _.find(map, item => { v || v === 0 ? Number(item[val]) === Number(v)) : '' }'; return res ? res[name] : '--'; }
-
表格中增加tips(表格中有排序,有其他hover效果)
-
filterDropdown: true, filterIcon: () => { return ( <Tooltip placement="top" overlayClassName={'data-table'}> <Icon type="question-circle" theme="outlined"/> </Tooltip> ); }
-
在table表格中配置
-
locale={{ filterTitle: '鼠标hover时显示的文字', }}
-
就可以在页面中显示
antd中select搜索遇到的问题
- 复现:1.select组件中的value和选项中的value值相同才能复现,
特别注意value的数据类型,number or string
- 复现:2.如果option中的数据是动态渲染的,需要保证数据来源的数组中有该条数据
list.map(val => (
<Option key={val.key} value={val.key}>{val.name}</Option>
))
- 搜索 即使你绑定了其他函数对list进行改变,输入的值会根据option中的value进行搜索展示。如果使用名字对list进行搜索,需将代码改为
list.map(val => (
<Option key={val.key} value={val.value}>{val.name}</Option>
))
根据表格中每项数据显示的时间判断展示内容是否可点
let flag ;
flag = item.pushStatus === 1 && moment()<moment(item.pushTime);
item.flag = flag;
return (<div>
{item.pushStatus === 0 ? releaseUp : (item.flag || item.pushStatus === 2 ? releaseDown : ' 下线 ')}
{item.pushStatus === 0 ? update : ' 修改 '}
{item.pushStatus === 0 ? remove : ' 删除'}
</div>)
ES6的活学活用
- 扩展运算加结构赋值
this.setState({ ... item })
- 报错
this.setState is not a functionat Object.handleChange [as dateCheck]
- 解决
注意this指向问题,是不是直接使用的function a () {}
建议使用箭头函数 () => {}
下拉单选
<Select
value={thisState.moduleId}
style={{width:157}}
size="small"
onChange={(val) => this.handleChange(val, 'moduleId')}
>
<Option value="" disabled>请选择</Option>
{ _.map(thisState.moduleList, item => <Option value={item.moduleId + ''} key={item.moduleId}>{item.moduleName}</Option>)}
</Select>
1.在Select中添加固定
添加getPopupContainer={triggerNode => triggerNode.parentNode}
,使其固定在父元素中
2.在DatePicker中添加固定
添加getCalendarContainer={triggerNode => triggerNode.parentNode}
,使其固定在父元素中
3.input框绑定中文事件
-
compositionstart是input框中自带的事件,当输入法为中文时,在input框中输入触发该事件
-
compositionend当输入时按空格,或者input框失去焦点,或者删除输入的内容时会触发该事件
4.underscore中_.isEmpty()
-
返回的是一个布尔值
-
可用于判断复杂数据类型是否为空
_.isEmpty([]);
=> true
_.isEmpty([1, 2, 3]);
=> false
_.isEmpty({});
=> true
_.isEmpty({1,2,3});
=> false
- 判断基本数据类型基本为true,除了含内容的字符串(‘不是空的字符串都可以’)
_.isEmpty('');
=> true
_.isEmpty(undefined);
=> true
_.isEmpty(null);
=> true
_.isEmpty(123);
=> true
_.isEmpty(false);
=> true
//这俩有点特殊
_.isEmpty(true);
=> true
_.isEmpty('aaa');
=> false
直接if判断
//
if('aa') {
console.log("'aa'为true");
}
if(123) {
console.log("123为true");
}
// 这些不展示
if('') {
console.log("这条不展示");
}
if(null) {
console.log("null为false");
}
if(undefined) {
console.log("undefined为false");
}
echarts中饼图大小位置调整
在series中设置
radius: '60%', // 半径
center: ['50%', '40%'], //左右上下的距离
几个特殊的转译
- undefined == null; // true
- 1 == true; // true
此时会把布尔类型的值转换为数字类型 true=1 false=0
- 2 == true; // false
- (!!2 == true); // true
- (!!0 == true); // false
- (!![] == true); // true
- (!!‘0’ == true); // true
!是表示非,能把数据类型转换为布尔类型
- 0 == false; // true
- 0 == ‘’; // true
- NaN == NaN; // false
- [] == false; // true
- [] == ![]; // true
减号,Number转换为数字
- null - 0; //0
- Number(null) // 0
第三方工具,用于组件之前通信,不受高阶组件影响(PubSub)
参考链接:https://www.cnblogs.com/lcosima/p/8626491.html
pubsubjs源码及使用详情:https://github.com/mroderick/PubSubJS
发送消息:PubSub.publish(名称,参数)
订阅消息:PubSub.subscribe(名称,函数)
取消订阅:PubSub.unsubscrib(名称)
a.首先引入包,在需要发送消息的位置,进行如下设置
PubSub.publish('PubSubmessag',this.state.increase);
b.订阅消息在要获获取值,或者要触发函数的地方使用如下方法
- 订阅消息PubSub.subscribe(名称,函数)中的函数有两个参数,分别对应发送消息PubSub.publish(名称,参数)中的名称和参数
PubSub.subscribe('PubSubmessage',(topic,message) => console.log(topic,message)
componentDidMount(){
//整体返回的值进行取消订阅
this.pubsub_token = PubSub.subscribe('PubSubmessage',(topic,message) => {
this.setState({
increase: message
});
});
}
c.使用PubSub.unsubscrib()取消订阅消息
componentWillUnmount(){
PubSub.unsubscribe(this.pubsub_token);
}