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

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阶段不更新踩坑,以及修改表单值方法。

参考 Ant Design的表单onChange阶段不更新踩坑,以及修改表单值方法_何其涛的博客-CSDN博客_antd form onchange

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

多看文档 Moment.js | Docs

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();

}

antd表单中的validateFields没有被执行可能的问题及解决_照物华的博客-CSDN博客_react validatefields

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先触发,即便同时绑定。)

如何解决blur事件和click事件冲突问题? - 知乎

楼主说的情况不是事件冲突,⽽是⻚⾯结构变化导致绑定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]);
    }

移动端键盘弹出没有顶起页面可以配置如下属性

form滚动到校验未通过位置

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值