ページ構成
- ヘッダー
- 左ナビ
- 右コンテンツ
前提条件
- 右コンテンツのみスクロール表示するため、右コンテンツのルートコンポーネントを
OverlayScrollbarsComponent
(npmモジュール)でラップしてスクロール制御している。 - このコンポーネントが3階層ほど<div>を生成して、実際には孫階層がスクロールを表示している。
// ↓厳密には若干異なりますが階層構造はこのような状態です。 <div id="anything"> <div> <div class="os-viewport"> // ←ここがスクロールバー </div> </div> </div
- 孫階層に
os-viewport
というクラスが付与されている。
やりたいこと(知りたいこと)
- 右コンテンツの深い階層でスクロール量によってフェードイン・アウト表示したいコンテンツを実装したい
- 実装した処理方法が良いか悪いか知識が足りず判断できないため、より良い方法があれば教えていただきたいです。
→ ref とか使ってうまくできたのかな?とかこれはやっちゃいけない(アンチパターン)だったとか・・・
以下のような構成(かなり簡略化しています)
js
1import React from 'react' 2import { HashRouter, Switch } from 'react-router-dom'; 3import { OverlayScrollbarsComponent } from 'overlayscrollbars-react'; 4 5const Router = () => { 6 const generateRoute = () => { 7 // do something 8 } 9 10 return ( 11 <HashRouter> 12 <Header /> 13 <LeftNav /> 14 <OverlayScrollbarsComponent id="anything"> 15 <Switch>{generateRoute()}</Switch> // generateRouteで生成された奥の方でスクロール量による処理を行う 16 </OverlayScrollbarsComponent> 17 </HashRouter> 18 ) 19} 20 21export default Router;
実際にやった実装
フェードイン・アウトするコンポーネント内にて、
1.OverlayScrollbarsComponent
のDOMを id で取得
2.1で取得したDOMから os-viewport
というクラス名が付与されているHTMLCollectionを取得
3.(とりあえず1つしかない前提で)os-viewport がついたDOMを取得
4.3で取得したDOMにスクロールイベントリスナーを登録
js
1useEffect(() => { 2 const target = getTargetElement(); 3 if (target) { 4 target.addEventLitener("scroll", event(target)) 5 } 6 return (() => { 7 if (target) { 8 target.removeEventLitener("scroll", event(target)) 9 } 10 }); 11}); 12 13const getTargetElement = () => { 14 targetParent = document.getElementById("anything"); 15 if (targetParent) { 16 const targetElements = targetParent.getElementsByClassName("os-viewport"); 17 if (targetElements.length > 0) { 18 return targetElements[0]; 19 } 20 } 21 return null; 22} 23 24const event = (target) => () => { 25 const pos = target.scrollTop; 26 if (pos > 100) { 27 setIsOpen(true); // ←フェードイン・アウトさせるフラグとして使用 28 } else { 29 setIsOpen(false); 30 } 31}
結果
ブラウザにて正常に動作はしましたが「う~ん、これでいいのか?」みたいな状態です。
より良い方法などがございましたらご教示頂けますと幸いです。
宜しくお願いいたします。

あなたの回答
tips
プレビュー