这里有新鲜出炉的 Javascript 教程,程序狗速度看过来!
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
这篇文章的内容是说说最近在工作中遇到过的常见的问题。主要是关于 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;
- }
- }
其中,
函数是我们的 action 处理函数。
- changeScrollFlag()
我们的函数节流
- 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 里使用
是并不能够接收到 props 的变化的!!!组件生命周期函数含有一个自己的参数。
- this.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')}
- >
在此,我们完成了一次从顶层组件触发事件,并做到函数节流,将事件一层层传递至底层展示型组件的一个过程。 最近一些关于前端开发的感慨
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。
来源: http://www.phperz.com/article/17/0511/329570.html