JavaScript触发onScroll事件的函数节流详解


Posted in Javascript onDecember 14, 2016

问题描述

常见的网站布局,顶部一个导航栏,我们假设本页面共有四个栏目:分别为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')}
>

在此,我们完成了一次从顶层组件触发事件,并做到函数节流,将事件一层层传递至底层展示型组件的一个过程。
最近一些关于前端开发的感慨

  1. 不要在组件中反复调用一个函数,这样会造成巨大的消耗!我们可以通过三元运算符、模板字符串做到的事情,请勿写一个新的函数。
  2. jsx不要太过于冗余。我们尽量写成变量的形式,不然页面结构复杂,不易于我们捕捉bug。
  3. 减少后端请求,能存cookie则存cookie,能存localStorge则存localStorge。
  4. 简单的组件尽量自己写,请勿使用别人的组件,否则在需求更改、样式调整上会出现巨大困难并做一些无意义的事儿。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

Javascript 相关文章推荐
关于JavaScript与HTML的交互事件
Apr 12 Javascript
解析Jquery取得iframe中元素的几种方法
Jul 04 Javascript
$.each与$().each的区别示例介绍
Mar 20 Javascript
基于jquery实现的自动补全功能
Mar 12 Javascript
基于javascript实现右下角浮动广告效果
Jan 08 Javascript
javascript基础知识分享之类与函数化
Feb 13 Javascript
实现React单页应用的方法详解
Aug 02 Javascript
BootStrapTable 单选及取值的实现方法
Jan 10 Javascript
超全面的javascript中变量命名规则
Feb 09 Javascript
Canvas实现放射线动画效果
Feb 15 Javascript
vue全局使用axios的方法实例详解
Nov 22 Javascript
Vue infinite update loop的问题解决
Apr 23 Javascript
AngularJS指令与指令之间的交互功能示例
Dec 14 #Javascript
AngularJS指令与控制器之间的交互功能示例
Dec 14 #Javascript
网站申请不到支付宝接口、微信接口,免接口收款实现方式几种解决办法
Dec 14 #Javascript
AngularJS定时器的使用与移除操作方法【interval与timeout】
Dec 14 #Javascript
本地Bootstrap文件字体图标引入却无法显示问题的解决方法
Apr 18 #Javascript
微信小程序中使元素占满整个屏幕高度实现方法
Dec 14 #Javascript
AngularJS基于ngInfiniteScroll实现下拉滚动加载的方法
Dec 14 #Javascript
You might like
深入解析php模板技术原理【一】
2008/01/10 PHP
PHP中数组的分组排序实例
2014/06/01 PHP
php操作XML、读取数据和写入数据的实现代码
2014/08/15 PHP
关于WordPress的SEO优化相关的一些PHP页面脚本技巧
2015/12/10 PHP
WordPress中创建用户角色的相关PHP函数使用详解
2015/12/25 PHP
删除重复数据的算法
2006/11/23 Javascript
面向对象的Javascript之三(封装和信息隐藏)
2012/01/27 Javascript
js页面跳转的问题(跳转到父页面、最外层页面、本页面)
2013/08/14 Javascript
可编辑下拉框的2种实现方式
2014/06/13 Javascript
nodejs分页类代码分享
2014/06/17 NodeJs
使用JS获取当前地理位置方法汇总
2014/12/18 Javascript
jQuery弹出层插件Lightbox_me使用指南
2015/04/21 Javascript
jquery+CSS3实现淘宝移动网页菜单效果
2015/08/31 Javascript
Bootstrap自定义文件上传下载样式
2016/05/26 Javascript
url传递的参数值中包含&amp;时,url自动截断问题的解决方法
2016/08/02 Javascript
Express与NodeJs创建服务器的两种方法
2017/02/06 NodeJs
基于javascript的异步编程实例详解
2017/04/10 Javascript
认识jQuery的Promise的具体使用方法
2017/10/10 jQuery
Vue 引入AMap高德地图的实现代码
2019/04/29 Javascript
详解babel升级到7.X采坑总结
2019/05/12 Javascript
python实现提取百度搜索结果的方法
2015/05/19 Python
Python smtplib实现发送邮件功能
2018/05/22 Python
关于Python turtle库使用时坐标的确定方法
2020/03/19 Python
Python+kivy BoxLayout布局示例代码详解
2020/12/28 Python
python性能测试工具locust的使用
2020/12/28 Python
用纯CSS3实现网页中常见的小箭头
2017/10/16 HTML / CSS
中东地区为妈妈们提供一切的头号购物目的地:Sprii
2018/05/06 全球购物
贪睡宠物用品:Snoozer Pet Products
2020/02/04 全球购物
P/Invoke是什么
2015/07/31 面试题
企业治理工作自我评价
2013/09/26 职场文书
出国签证在职证明
2014/01/16 职场文书
法学院方阵解说词
2014/01/29 职场文书
高中生职业生涯规划书
2014/02/24 职场文书
财务会计大学生自我评价
2014/04/09 职场文书
公司员工违纪检讨书
2015/05/05 职场文书
css样式important规则的正确使用方式
2022/06/10 HTML / CSS