ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript で onScroll イベントをトリガーする関数スロットルの詳細な説明

JavaScript で onScroll イベントをトリガーする関数スロットルの詳細な説明

高洛峰
高洛峰オリジナル
2016-12-29 10:19:261519ブラウズ

問題の説明

一般的な Web サイトのレイアウト、上部にナビゲーション バーがあるとします。このページには A、B、C、D の 4 つの列があるとします。A をクリックすると、アンカーが列 A にジャンプします。今度は、一番上のボタン A が強調表示され、B をクリックすると、アンカーが列 B にジャンプし、メイン コンポーネント内をスクロールすると、一番上のボタン B が強調表示され、モジュール B にスクロールすると、ボタン B が強調表示されます。上記は開発中によく遭遇するモデルです。過去にフロントエンド開発に jQuery を使用したことがある場合は、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 />

メインコンポーネントにonScrollイベントを設定し、アクションをトリガーし、reduxを通じてステータスの変更をサブコンポーネントに渡します。

私のスクロールイベントトリガー関数は次のようなものです(if elseの長いリストを無視すると、これが午後のバグに対する究極の解決策です。この記事では詳細には触れません)

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()この関数はアクション ハンドラー関数です。

私たちの関数 throttling

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

私たちのスロットリング関数は、タイムスタンプを設定する関数を返します。タイムスタンプの差が小さい場合は、タイムスタンプの差のみを行います。差が大きい場合は、タイマーをクリアしてスクロールをトリガーします関数。これは非常に簡単なようですが、確かに非常に簡単です。

それでは、サブコンポーネントで他に何をする必要があるでしょうか?

アクションの受信

第 2 レベルのコンテナ コンポーネントはアクションを受け取り、第 2 レベルのコンテナ コンポーネントを介して props を第 3 レベルの表示コンポーネントに渡します。

この小道具をcomponentWillReceivePropsで受け取る必要があります。

componentWillReceiveProps で this.props を使用しても、props の変更は受け取らないことに注意してください。 ! !コンポーネントのライフサイクル関数には、独自のパラメーターが含まれています。

componentWillReceiveProps(nextProps) {
 // 在compoWillReceiveProps里接收到Main组件里所触发onScroll事件的改变activebtn样式的index
 // 并且设置为本组件的state
 this.setState({
 activebtn: nextProps.scrollFlag.scrollIndex,
 });
}

どのボタンを強調表示するかは状態によって制御されます。それは番号です。

ナビゲーション バーのスタイルを変更する

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

ここで、最上位コンポーネントからイベントをトリガーし、関数を調整し、イベントをレイヤーごとに基になる表示コンポーネントに渡すプロセスが完了しました。
フロントエンド開発について最近感じたこと

コンポーネント内で関数を繰り返し呼び出さないでください。大量の消費が発生します。三項演算子とテンプレート文字列を使用して実行できる新しい関数を作成しないでください。

jsx 冗長になりすぎないでください。変数の形式で記述するようにしています。そうしないと、ページ構造が複雑になり、バグを捕捉するのが困難になります。

Cookie を保存できる場合は、localStorge を保存します。

他の人のコンポーネントを使用しないでください。そうしないと、要件の変更やスタイルの調整が非常に困難になり、意味のないことを行うことになります。

概要

上記がこの記事の全内容です。この記事の内容が皆さんの学習や仕事に少しでも役立つことを願っています。ご質問がある場合は、メッセージを残して連絡してください。


JavaScript で onScroll イベントをトリガーする関数スロットルの詳細な説明については、PHP 中国語 Web サイトに注目してください。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。