JavaScript触发onScroll事件的函数节流详解
问题描述
常见的网站布局,顶部一个导航栏,我们假设本页面共有四个栏目:分别为a、b、c、d,我们点击a,锚点跳转至a栏目,同时顶部的a按钮高亮;点击b,锚点跳转至b栏目,同时顶部的b按钮高亮;我们在main组件里面滚动,滚动到b模块时,b按钮高亮。以上是我们经常会在开发中遇到的一个模型。如果是在以前,用jquery作前端开发的话,实在是太熟悉不过了。
解决方案
主要想谈谈在react组件化开发中的性能优化方法。
我们的页面结构是这样的
<div classname={style.main} id="main" ref={(main) => { this.main = main; }} onscroll={ ((/detail/.test(this.props.location.pathname))) ? (() => this.throttle()()) : null } > {this.props.children} <footer />
我们在main组件里设定onscroll事件,在这个事件中,我们触发action,通过redux将状态的变化传递到子组件。
我的scroll事件触发函数是这样的(忽略一长串的if else,这是一个解决了一下午的bug的终极解决方案,此文不做累述)
handlescroll() { const { changescrollflag } = this.props.actions; // 根据滚动距离修改titlebox的样式 const { basicinformation, holderinformation, mainpeople, changerecord } = { basicinformation: document.getelementbyid('basicinformation').offsettop - 121, holderinformation: document.getelementbyid('holderinformation').offsettop - 121, mainpeople: document.getelementbyid('mainpeople').offsettop - 121, changerecord: document.getelementbyid('changerecord').offsettop - 121, }; if (window.screen.availheight > this.main.scrolltop) { document.getelementbyid('gototop').style.display = 'none'; } else { document.getelementbyid('gototop').style.display = 'block'; } // 得到基础信息区域、股东信息区域、主要人员区域、变更记录区域的offsettop,我们把它用来跟main的scrolltop比较 // 比较的结果触发action,改变titlebox组件样式 if (this.main.scrolltop < holderinformation) { // 基础信息区域 if (basicinformation === -121) { // 如果基础信息模块不存在,我们什么也不做(当然理论上基础信息模块应该是会有的) return; } changescrollflag(1); return; } else if (this.main.scrolltop < mainpeople) { // 股东信息区域 changescrollflag(2); if (holderinformation === -121) { // 如果股东信息栏目不存在,在滚动的时候我们不应该强行把tilebox的高亮按钮设置为holderinformation // 因为holdinformation并不存在,我们跳到前一个按钮,让基础信息按钮高亮 changescrollflag(1); return; } return; } else if (this.main.scrolltop < changerecord) { // 主要人员区域 changescrollflag(3); if (mainpeople === -121) { // 如果主要人员栏目不存在,在滚动的时候我们不应该强行把tilebox的高亮按钮设置为mainpeople // mainpeople并不存在,我们跳到前一个按钮,让基础信息按钮高亮 changescrollflag(2); if (holderinformation === -121) { // 如果主要人员栏目不存在,而且连股东信息栏目也没有,我们跳到高亮基础信息栏目 changescrollflag(1); return; } return; } return; } else if (this.main.scrolltop > changerecord) { // 与上面同理 // 变更记录区域 changescrollflag(4); if (changerecord === -121) { changescrollflag(3); if (mainpeople === -121) { changescrollflag(2); if (holderinformation === -121) { changescrollflag(1); return; } return; } return; } return; } }
其中,changescrollflag()
函数是我们的action处理函数。
我们的函数节流
throttle() { // onscroll函数节流 let previous = 0; // previous初始设置上一次调用 onscroll 函数时间点为 0。 let timeout; const wait = 250; // 250毫秒触发一次 return () => { const now = date.now(); const remaining = wait - (now - previous); if (remaining <= 0) { if (timeout) { window.cleartimeout(timeout); } previous = now; timeout = null; this.handlescroll(); } else if (!timeout) { timeout = window.settimeout(this.handlescroll, wait); } }; }
我们的节流函数返回一个函数,设定一个时间戳,如果我们时间戳的差值较小,我们什么也不做,但我们的时间戳的差值较大,清除定时器,触发scroll函数。这样看起来似乎挺简单,对,确实是挺简单的。
那么在子组件我们还需要怎么做呢?
接收action
二级容器型组件接收action,通过二级容器型组件传递props至三级展示型组件。
我们一定要在componentwillreceiveprops接收到这个props。
记住,在componentwillreceiveprops里使用this.props
是并不能够接收到props的变化的!!!组件生命周期函数含有一个自己的参数。
componentwillreceiveprops(nextprops) { // 在compowillreceiveprops里接收到main组件里所触发onscroll事件的改变activebtn样式的index // 并且设置为本组件的state this.setstate({ activebtn: nextprops.scrollflag.scrollindex, }); }
我们的state控制我们高亮的按钮是第几个,它是一个数字。
更改导航条的样式
在这里,我使用了react周边的库:classnames,详情参见其api。
<span classname={classnames({ [style.informationactive]: (this.state.activebtn === 1), })} onclick={() => this.handleclick(1, 'basicinformation')} >
在此,我们完成了一次从顶层组件触发事件,并做到函数节流,将事件一层层传递至底层展示型组件的一个过程。
最近一些关于前端开发的感慨
- 不要在组件中反复调用一个函数,这样会造成巨大的消耗!我们可以通过三元运算符、模板字符串做到的事情,请勿写一个新的函数。
- jsx不要太过于冗余。我们尽量写成变量的形式,不然页面结构复杂,不易于我们捕捉bug。
- 减少后端请求,能存cookie则存cookie,能存localstorge则存localstorge。
- 简单的组件尽量自己写,请勿使用别人的组件,否则在需求更改、样式调整上会出现巨大困难并做一些无意义的事儿。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。
推荐阅读
-
JavaScript触发onScroll事件的函数节流详解
-
ES6中javascript实现函数绑定及类的事件绑定功能详解
-
JavaScript触发onScroll事件的函数节流详解
-
在JavaScript里防止事件函数高频触发和高频调用的方法_javascript技巧
-
详解ES6中javascript实现函数绑定及类的事件绑定功能
-
JavaScript触发onScroll事件的函数节流详解
-
在JavaScript里防止事件函数高频触发和高频调用的方法_javascript技巧
-
javascript函数的节流throttle与防抖debounce详解
-
JavaScript触发onScroll事件的函数节流详解
-
详解javascript函数的节流与防抖