質問編集履歴

1 スクロールバーを表示させている部分の詳細を記載

takuya_am

takuya_am score 15

2021/03/05 11:40  投稿

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

    37528 questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • Node.js

    4573 questions

    Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

  • TypeScript

    1904 questions

    TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

  • React.js

    3813 questions

    Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る