日常开发小技巧经验汇总(持续更新中)

it2022-05-08  15

 

react jsx 中使用 switch case 示例

在JSX的render html中无法写类似if,switch这样的语法,但是可以写函数或者三元表达式。所以可以利用一个立即执行的匿名函数来包装你的方法。

<div> <span>适用平台:</span> <span>{(() => { switch (currentItems.usePlatform) { case 0: return '全平台可用' case 1: return '淘宝' case 2: return '美团' case 3: return '爱奇艺' case 4: return '腾讯' default: return null } } )()}</span> </div>

去除数组中的空数组 

// 去除数组中的空数组 var arr = [undefined,undefined,1,'','false',false,true,null,'null']; arr.filter(item=>item) console.log(arr.filter(item=>item)) // [1, "false", true, "null"]

跳出forEach循环的方法,因为forEach中不能使用continue与break,所以可以用try,catch去抛出一个异常,然后捕获的方式去终断它。

var arr = [1,2,3,5]; try { arr.forEach(item => { if (item === 2) { throw new Error('错误') } console.log(item); // 1 }); } catch (e) { console.log(e.message); // 错误 } console.log('之后的执行函数') // 之后的执行函数

也可以使用some,every,find来跳出循环,every return false可以跳出循环, some,find  return true可以跳出循环。

var arr = [1,2,3,5]; arr.some(item => { console.log('item', item) // 1 2 return item === 2 }) console.log('之后的执行函数') var arr = [1,2,3,5]; arr.find(item => { console.log('item', item) // 1 2 return item === 2 }) console.log('之后的执行函数')

 

 

一个list数组,算出order相同下相应scale相加的总和。使用reduce可以更加简单方便。

var list = [{order:1, scale:10}, {order:2, scale:200}, {order:1, scale:10}, {order:1, scale:80}, {order:3, scale:120}]; var c = list.reduce((pre, cur) => (pre[cur.order] = (pre[cur.order] || 0) + cur.scale) && pre, {}) // 等价于 var c = list.reduce((pre, cur) => { pre[cur.order] = (pre[cur.order] || 0) + cur.scale; return pre; }, {}); console.log(c) // {1: 100, 2: 200, 3: 120}

 

已知年月,求该月共多少天?

在写日历组件时,曾遇到 已知年月,求该月共多少天? 这样的需求。

最开始思路会是:

先判断该年份是否是闰年,来处理 2 月份情况,闰年 2 月共 29 天,非闰年 2 月共 28 天再判断其他月份,如 1 月共 31 天,4 月共 30 天

代码就不一一列出了,思路代码啥的没啥问题。

这里其实有种更简便的方法,借助 Date API 处理日期溢出时,会自动往后推延响应时间的规则,直接上代码:

// month 值需对应实际月份减一,如实际 2 月,month 为 1,实际 3 月,month 为 2 function getMonthCountDay (year, month) { return 32 - new Date(year, month, 32).getDate() }

验证下:

// 求闰年的 2 月份总天数 getMonthCountDay(2000, 1) // 29 // 求 1 月份总天数 getMonthCountDay(2000, 0) // 31 getMonthCountDay(2001, 0) // 31 // 求 4 月份总天数 getMonthCountDay(2000, 3) // 30 getMonthCountDay(2001, 3) // 30

Date API 处理日期溢出时,会自动往后推延响应时间的规则,那么具体的规则内容是什么?

类似于加法进位,减法退位。

new Date(2019, 0, 50)其中0代表1月,1月只有31天,则多出来的19天会被加到2月,结果是2019年2月19日。new Date(2019, 20, 10),1年只有12个月,多出来的9个月会被加到2020年,结果是2020年9月10日new Date(2019, -2, 10),2019年1月10日往前推2个月,结果为2018年11月10日new Date(2019, 2, -2),2019年3月1日往前推2天,结果为2019年2月26日以上可以混用

 

antd 多项验证规则

{getFieldDecorator(key, { initialValue: data ? data[key] : '', rules: [{ required: itemProps.required, message: itemProps.placeholder, pattern: itemProps.pattern }, ...itemProps.rules], }) // reducer required: true, placeholder: '请输入', rules: [ { pattern: /^[\u4e00-\u9fa5_a-zA-Z0-9]+$/, message: '只能为中文,字母,数字', }, { pattern: /^[\u4e00-\u9fa5_a-zA-Z0-9]+$/, message: '只能为中文,字母,数字', }, ],

 

多层解构赋值

const obj = { pageStore: { policyObj: { policy: 1 } } } const { pageStore: { policyObj: { policy: info } } } = obj; console.log(info) // 1 相当于声明了info,且policy 赋值给 info const { pageStore: { policyObj: { policy } } } = obj; console.log(policy) // 1

 

三元表达式取值的两种写法

getFieldDecorator(key, key === 'practiceCertiEffectiveStop' ? { initialValue: data && data[key] ? moment(data[key]) : moment('9999-12-31'), rules: [ { required: itemProps.required, message: itemProps.message }, ], } : { initialValue: data && data[key] ? moment(data[key]) : null, rules: [ { required: itemProps.required, message: itemProps.message }, ], }) getFieldDecorator(key, { // eslint-disable-next-line no-nested-ternary initialValue: data && data[key] ? moment(data[key]) : (key ==='practiceCertiEffectiveStop' ? moment('9999-12-31') : null), rules: [ { required: itemProps.required, message: itemProps.message }, ], }) // bad const foo = maybe1 > maybe2 ? "bar" : value1 > value2 ? "baz" : null; // 分离为两个三目表达式 const maybeNull = value1 > value2 ? 'baz' : null; // better const foo = maybe1 > maybe2 ? 'bar' : maybeNull; // best const foo = maybe1 > maybe2 ? 'bar' : maybeNull;

文字超出三行显示...,鼠标放上显示全部内容

<span title={record.remark} style={{ display: '-webkit-box', WebkitBoxOrient: 'vertical',WebkitLineClamp: '3', overflow: 'hidden', wordWrap: 'break-word', wordBreak: 'break-word', }} > {record.remark} </span> div { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; text-overflow: ellipsis; word-wrap: break-word; word-break: break-word; overflow: hidden; }

https://github.com/ant-design/ant-design/issues/13825 

antd 表格设置width不起作用

 

时间戳转化BUG

在本地时间转化为时间戳的时候,要使用/,如用new Date('2019-11-4 23:59:59')的时候,在PC端没有问题,但是手机端会出现报错。

const endTime = new Date('2019/11/4 23:59:59'); 

 

git相关问题

之前升级下了package.json里面的包,结果一直提示如下报错

.git/hooks/pre-commit: line 2: ./node_modules/_pre-commit@1.2.2@pre-commit/hook: No such file or directory

其实解决办法很简单,rm -rf .git/hooks/pre-commit,删除掉这个东西然后重新install一下node_modules就可以了。

 

美化浏览器自带的 radio ,checkbox 属性

第一种办法是常见的  将真实的radio,checkbox等元素透明度设为0,定位在美化的图片上面,然后去操作。

第二种的话可以利用css去操作,核心

一是伪类选择器 :checked,表示对应控件元素(单选框或是复选框)选中时的样式;二就是加号 + 相邻兄弟选择器,这个符号表示选择后面的兄弟节点。于是,两者配合,就可以轻松自如控制后面元素的显示或者隐藏,或是其他样式了。

而如何让单复选框选中和不选中了,那就是 label 标签了哈,for 属性锚定对应的单选框或是复选框,然后点击这里的 label 标签元素的时候,对应的单复选框就会选中或是取消选中。然后,就有上面的效果啦!

<style> .checkbox-name { vertical-align: middle; font-size: 16px; } .checkbox-beauty { width: 15px; height: 15px; line-height: 15px; text-align: center; border: 1px solid #ccc; display: inline-block; margin: 0 15px 0 3px; vertical-align: middle; } input[type="checkbox"]:checked+.checkbox-beauty::after { content: '✓'; font-size: 16px; font-weight: bold; color: green; } .checkbox-beauty:hover { box-shadow: 0 0 7px green; } </style> <div> <span class="checkbox-name">香蕉</span> <input type="checkbox" name="checkboxName" id="checkboxName2" hidden/> <label for="checkboxName2" class="checkbox-beauty"></label> </div>

 

input flex:1 无法自适应

在发送验证码的场景中,一般最外层的盒子设置为弹性盒子,左边和右边的写成固定宽度,中间的input输入框设置为flex:1,希望input的宽度是所剩下的长度,结果是它比所剩下的长度要大,验证码这三个字就显示成两行了

原因是:input兼容弹性盒子有问题,它会有一个自己默认的最小长度,所以会导致验证码显示成两行

解决办法:我们可以给input输入框加一个div父元素,然后这个div设置flex:1,input设置width:100%;即可解决问题  

 

react中的事件对象event中target在控制台查看为null,但是event.target却能获取到目标元素,为什么?

 

这是因为React里面的事件并不是真实的DOM事件,而是自己在原生DOM事件上封装的合成事件。 合成事件是由事件池来管理的,合成事件对象可能会被重用,合成事件的所有属性也会随之被清空。所以当在异步处理程序(如setTimeout等等)中或者浏览器控制台中去访问合成事件的属性,有可能就是空的。 上面的答案中给出的方案:event.persist(),其实就是将当前的合成事件从事件池中移除了,所以能够继续保有对该事件的引用以及仍然能访问该事件的属性。

 

react父组件调用,子(孙)组件的方法

export default class Parent extends Component { render() { return( <div> <Child onRef={this.onRef} /> <button onClick={this.click} >click</button> </div> ) } onRef = (ref) => { this.child = ref } click = (e) => { this.child.myName() } } class Child extends Component { componentDidMount(){ this.props.onRef(this) } myName = () => alert('xiaohesong') render() { return ('woqu') } }

解决IOS8 或者安卓4.4    es6 转换报错。

利用getValueFromEvent 再输入的时候可以做很多操作,比如去除空格什么的,比在onblur里面写要方便很多

<Form.Item key="libName" label="险种名称" > {getFieldDecorator(`data[${val}].libName`, { initialValue: '', getValueFromEvent: (event) => { return event.target.value.trim(); }, })( <Input />, )} </Form.Item>

当使用了PureComponent时,要格式注意,如果页面中有浅比较,设置setState不会触发render的执行,即数据虽然变了但页面不会更新。

// 类似这种数据,不会触发更新 fruit: [{ type: 'bannana', count: 0 },{ type: 'apple', count: 0 }] fruit.splice(0, 1); this.setState({ fruit, }) // 解决办法,深拷贝fruit操作,或者页面不要使用 PureComponent

解决办法:  使用深拷贝,或者页面不要使用 PureComponent

 

VSCODE  启用本地服务,安装  npm install http-server -g ,启动 http-server 即可。

 

类似这种多表格验证的,最好是使用如下的方法

声明两个数组, 一个数组 arr: [0], // 数组key 来存放循环key值,一个 renderDetailList:[] // 数据list,用来渲染数据。注意的是存放key的这个数组是必须的,且新增要用如下方法,保持它是自增的。之前使用index作为循环的key值,就会出现删除某列以后,key值绑定混乱的情况。

PS: 之前试过将每一列单独抽一个子组件来实现,都是一个独立的form表单,最后提交的时候再去拼接数组。也可以实现功能,但是会很繁琐,不建议使用。

if (arr && arr.length > 0) { arr.push(arr[arr.length - 1] + 1); } else { arr.push(0); }

 

{ arr && arr.map((val, i) => { return ( <div className="product-detail-container" key={val}> <Form layout="inline"> <Form.Item key="lib" label="险种大类" > {getFieldDecorator(`data[${val}].lib`, { initialValue: renderList[i] && renderList[i].lib ? renderList[i].lib : null, rules: [ { required: true, message: '不能为空' }, ], })( <Select> <Select.Option key="1" value="1">重疾</Select.Option> <Select.Option key="2" value="2">定寿</Select.Option> <Select.Option key="2" value="3">意外</Select.Option> </Select>, )} </Form.Item> }

 

antd Select利用labelInValue属性使选择返回对象

function handleChange(value) { console.log(value); // { key: "lucy", label: "Lucy (101)" } } ReactDOM.render( <Select labelInValue defaultValue={{ key: 'lucy' }} style={{ width: 120 }} onChange={handleChange} > <Option value="jack">Jack (100)</Option> <Option value="lucy">Lucy (101)</Option> </Select>, mountNode, );

默认情况下 onChange 里只能拿到 value,如果需要拿到选中的节点文本 label,可以使用 labelInValue 属性。

选中项的 label 会被包装到 value 中传递给 onChange 等函数,此时 value 是一个对象。

 

css中第一行首字变大,顶部无法对齐,或者有时因为设置了font-size,子元素无法在容器与顶部齐平。设置喜爱vertical-align: top就好了。

 

p:first-letter {     font-size:20px;     vertical-align:top; }

 

react中,有时候需要在你disabled中写一个函数来返回布尔值,但是却一直报错。(原因是我的函数里面有异步操作,比如setTiomout,导致在渲染的时候disabled还没有返回值,所以报错 )  解决的话 这个函数必须是个同步函数。

<DatePicker style={{ width: 120 }} disabled={this.disabledMarkDate(i, list[i].disabled, disabled)} disabledDate={(e) => this.disabledDate(e, i)} />,

 

 

接受setTimeout中的返回值, 用回调的方法或者包一层promise

promise

// 校验是否是无效规则 isInvalid = (index) => { const { form: { getFieldsValue } } = this.props; // 因为表单的list是异步更新的,所以需要在setTimeout里面去才能访问到更新后的值 return new Promise(((resolve) => { setTimeout(() => { const itemVal = getFieldsValue().data[index]; const flag = itemVal.checkStatus === 0; // 将是否禁用开关返回 resolve(flag); }, 0); })); }; // 预停用时间禁用 (新增规则和修改无效规则时,此字段不可录入) disabledMarkDate = async (index, listDisabled, disabled) => { const flag = await this.isInvalid(index); return flag; };

回调

checkOver(item,callback){ setTimeout(() => { let check = XXXX; callback&&callback(check) }, 1) } //调用 checkOver(item,function(check){ console.log(check) })

 

有时候在表单某个元素onChange的时候去获取表单的值,发现并不能获取到最新的值。最简单的办法是可以用setTimeout里面去异步就可以获取到。或者也可以使用表单的onValuesChange去实时获取每次表单更新时候得值。

 Ant Design的表单onChange阶段不更新踩坑,以及修改表单值方法。

参考 https://blog.csdn.net/deng1456694385/article/details/86090884

 

 

antd 日期组件 (选择范围  大于等于开始时间,小于等于结束时间)。大于等于开始时间很简单,结果小于等于结束时间试了半天才知道endOf('day')就可以了  

多看文档 https://momentjs.com/docs/#/parsing/is-valid/

disabledDate = (current) => { return current < moment(startTime) || current > moment(endTime).endOf('day'); };

 

 

antd表单中的validateFields没有被执行原因(多半是自定义校验写的有问题,callback有情况没有执行)

之前代码是这样写的,发现validateFields有事一直没触发,仔细检查是自己的 itemVal可能为undefined,导致callback永远不会被执行引起的

isExpiryRequred = (rule, value, callback, index) => { const { form: { getFieldsValue } } = this.props; const itemVal = getFieldsValue().data[index]; // 类型为活动,且状态无效时,必录终止时间 if (!value && itemVal.type === '1' && itemVal.commissionStatus === 0) { return callback('不能为空'); } return callback(); };

在最开始时候 加个itemVal判断就行了

if (!itemVal) {

return callback();

}

https://blog.csdn.net/daihaoxin/article/details/106130597

 

antd table 行点击事件以及高亮显示选中行的背景颜色

rowClassName: 表格行的类名, 比如通过this.setRowClassName方法添加类名

onRow: 用于给表格添加事件, 如onClick, onMouseEnter 等内部事件

// 选中行 onClickRow = (record) => { return { onClick: () => { this.setState({ rowId: record.id, }); }, }; } setRowClassName = (record) => { return record.id === this.state.rowId ? 'clickRowStyl' : ''; } <Table pagination={dataPagination} columns={this.dataTableColumns} dataSource={this.dataSource} locale={{ emptyText: <NoContent/> }} onRow={this.onClickRow} rowClassName={this.setRowClassName} /> // 被选中的表格行的样式 .active { background-color #00b4ed; }

 

sticky 踩坑问题

1、父元素不能overflow:hidden或者overflow:auto属性。

2、必须指定top、bottom、left、right4个值之一,否则只会处于相对定位

3、父元素的高度不能低于sticky元素的高度

4、sticky元素仅在其父元素内生效

5、父元素设置display: flex,会导致子元素sticky失效,所以可用float布局代替

<style> .box { height: 1000px; } h1 { position: sticky; top: 100px; } </style> <body> <div class="box"> <h1>sticky</h1> </div> </body>

如上,父元素box足够高,能撑开滚动条,就可以实现固定定位了,

但是如果里面再包一层div那就不行了(sticky元素仅在其父元素内生效)

<style> .box { height: 1000px; } h1 { position: sticky; top: 100px; } </style> <body> <div class="box"> <div> <h1>sticky</h1> </div> </div> </body>

 

Moment取最后一天,第一天方法 

// 当月第一天开始时间 console.log(month.startOf('month').startOf('day').format('YYYY-MM-DD HH:mm:ss')); // 当月最后一天结束时间 console.log(month.endOf('month').endOf('day').format('YYYY-MM-DD HH:mm:ss'));

 

onblur和onclick事件冲突。(form中有一个input有失焦的校验,如果是在input聚焦的时候,直接点击保存提交表单,会发现提交的click没有触发,而是触发了input的失焦事件,原因是由于js的单线程机制和事件响应优先级的问题,onBlur总是比onClick先触发,即便同时绑定。)

https://www.zhihu.com/question/29623049

楼主说的情况不是事件冲突,⽽是⻚⾯结构变化导致绑定click的按钮没有被click到(这个你可以在click的 handler中打断点来验证)。 详细点说就是:点击时候input触发了blur,显示了错误消息(或其他⻚⾯结构变化),⽽这时候再松开⿏ 标,完成Click,但此时⿏标已经不在被绑定Click的元素上了,所以也就⽆法触发Click事件。 理解了Click事件的两步,这个问题就容易解决了,解决⽅案是⽤mousedown来代替click来绑定事件

 

解决方法1:

在失焦的事件里面设置个setTimeout延迟,保证在click之后才会触发,这样再点击提交click的时候,就会优于onBlur先触发onClick事件。

var tid; onBlur = function(){ tid = setTimeout(function(){ //do blur save }, 50); }; onClick = function(){ clearTimeout(tid); //do click save }

 解决方法2:

将onClick换成onMouseDown

 

PC浏览器预览打开doc,excel等格式方法。(移动端默认就可以打开) ,以下都是针对PC端的说明:

https://view.officeapps.live.com/op/view.aspx?src=${你文档的地址}` // 利用微软的在线文档打开

(如果是pdf等浏览器识别的文件,正常点链接的话浏览器会尝试打开文件,直接下载文件,) 

下面download的a标签,在同域情况下(资源(也就是图片) 和当前域名是同域的情况下),就会优先下载,如果跨域就会在浏览器中打开,但如果是浏览器不支持的格式依旧会下载(如zip,doc,excel等浏览器打不开的格式)。

比如在同域下,download PDF、图片, 就会是下载文件,而跨域就会直接在浏览器中打开。

<a href="money.PNG" download="a">xiazia</a>

总结一句话, 资源文件同域下载,跨域优先打开,打不开就下载。

 

 

sort实现数组内对象排序

/**      * @description: 根据数组内对象某一属性(number类型)进行排序      * @param {*} source 目标数组      * @param {*} sortField 排序属性      * @param {*} sortType ASC DESC 默认升序      * @return {*}      */     const sortFn = (source, sortField, sortBy = 'ASC') => {         return source.sort((a, b) => sortBy === 'ASC' ? a[sortField] - b[sortField] : b[sortField] - a[sortField]);     }

 


最新回复(0)