質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.80%

スクロール量に応じて表示・非表示させるコンテンツの実装方法

受付中

回答 0

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 220

score 15

ページ構成

  • ヘッダー
  • 左ナビ
  • 右コンテンツ

前提条件

  • 右コンテンツのみスクロール表示するため、右コンテンツのルートコンポーネントをOverlayScrollbarsComponent(npmモジュール)でラップしてスクロール制御している。
  • このコンポーネントが3階層ほど<div>を生成して、実際には孫階層がスクロールを表示している。
// ↓厳密には若干異なりますが階層構造はこのような状態です。
<div id="anything">
  <div>
    <div class="os-viewport"> // ←ここがスクロールバー
    </div>
  </div>
</div
  • 孫階層に os-viewport というクラスが付与されている。

やりたいこと(知りたいこと)

  • 右コンテンツの深い階層でスクロール量によってフェードイン・アウト表示したいコンテンツを実装したい
  • 実装した処理方法が良いか悪いか知識が足りず判断できないため、より良い方法があれば教えていただきたいです。
    → ref とか使ってうまくできたのかな?とかこれはやっちゃいけない(アンチパターン)だったとか・・・

以下のような構成(かなり簡略化しています)

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にスクロールイベントリスナーを登録

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

結果

ブラウザにて正常に動作はしましたが「う~ん、これでいいのか?」みたいな状態です。

より良い方法などがございましたらご教示頂けますと幸いです。
宜しくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.80%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る