首頁  >  文章  >  web前端  >  JavaScript觸發onScroll事件的函數節流詳解

JavaScript觸發onScroll事件的函數節流詳解

高洛峰
高洛峰原創
2016-12-29 10:19:261519瀏覽

問題描述

常見的網站佈局,頂部一個導航欄,我們假設本頁共有四個欄位:分別為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(&#39;basicinformation&#39;).offsetTop - 121,
 holderinformation: document.getElementById(&#39;holderinformation&#39;).offsetTop - 121,
 mainpeople: document.getElementById(&#39;mainpeople&#39;).offsetTop - 121,
 changerecord: document.getElementById(&#39;changerecord&#39;).offsetTop - 121,
 };
 if (window.screen.availHeight > this.main.scrollTop) {
 document.getElementById(&#39;gototop&#39;).style.display = &#39;none&#39;;
 } else {
 document.getElementById(&#39;gototop&#39;).style.display = &#39;block&#39;;
 }
 // 得到基础信息区域、股东信息区域、主要人员区域、变更记录区域的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控制我們高亮的按鈕是第幾個,它是一個數字。

更改導航條的樣式

<span
 className={classnames({
 [style.informationactive]: (this.state.activebtn === 1),
 })}
 onClick={() => this.handleClick(1, &#39;basicinformation&#39;)}
>

在此,我們完成了一次從頂層組件觸發事件,並做到函數節流,將事件一層層傳遞至底層展示型組件的一個過程。
最近一些關於前端開發的感慨

不要在元件中反覆調用一個函數,這樣會造成巨大的消耗!我們可以透過三元運算子、模板字串做到的事情,請勿寫一個新的函數。

jsx不要太過於冗餘。我們盡量寫成變數的形式,不然頁面結構複雜,不容易我們捕捉bug。

減少後端請求,能存cookie則存cookie,能存localStorge則存localStorge。

簡單的組件盡量自己寫,請勿使用別人的組件,否則在需求更改、樣式調整上會出現巨大困難並做一些無意義的事兒。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或工作能帶來一定的幫助,如果有疑問大家可以留言交流。


更多JavaScript觸發onScroll事件的函數節流詳解相關文章請關注PHP中文網!


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn