反応コンポーネントがビューポートの境界から外れているかどうかを検出する

14158 ワード

写真でErol Ahmed on Unsplash
それで、最近、私は、「コンポーネントがビューポートの境界から外れているかどうかを検出するにはどうしたらいいか」と尋ねました.私がこの質問をしていた理由は、私がツールヒント、ドロップダウン、メニュー項目などのように、彼らが視界にいないならば、どのようにコンポーネントを見つけて、動かすかについてわかっていたかったからでした.
初めに私はuseLayoutEffect フックは良いオプションになっていたかもしれませんが、フックができなかった場合には例えばドラグガブリでした部品では動作しません😃) をドラッグし、フックの依存性として追加します.また、アニメーションやホバーの効果などのCSSによって制御された何かのために本当に動作しません.
それで、JavaScriptに遭遇するまで、私は研究し、Googglingして、ものをテストし続けましたMutationObserver .

A built-in object that observes a DOM element, firing a callback in case of modifications - W3 Schools


私は、AであるふりをするつもりでありませんMutationObserver エキスパートしかし、私はリンクしますthis article 場合は、それについての詳細を学びたい場合.
基本的に、私たちはMutationObserver コンポーネントへの変更を監視し、コンポーネントの位置を確認します.

コードに病棟で!⚔️


フックセットアップ🏗️


あなたは少し脅迫される前にフックを書いていない場合は、実際にはかなり簡単です.カスタムフックは、他の反応フックを利用/呼び出しできる機能です.
export const useOutOfBounds = () => {
    // Cool code goes here 😃
};
私たちのフックはパラメータを受け入れるつもりはないので、関数定義にそれらを含めるつもりはありません.ここで注意することは関数名です.useOutOfBounds , 反応は、カスタムフックの名前を開始する必要がありますuse さもなければ、それはあいまいなエラーを投げます.

効果、状態、オブザーバー🕵🏽‍♂️, フックリターン


これがカスタムフックであるので、私たちは他のフック、例えばuseState , useRef , and useEffect それはまさに我々がしていることです.
export const useOutOfBounds = () => {
    const componentRef = React.useRef();
    const [isOutOfBounds, setIsOutOfBounds] = React.useState({
        top: 0,
        bottom: 0,
        left: 0,
        right: 0
    });
    const observer = new MutationObserver(mutationObserverCallback); //We'll define this callback in a second

    React.useEffect(() => {
        if (componentRef.current) {
            observer.observe(componentRef.current, { attributes: true, childList: true, subtree: true });
        }

        return () => observer.disconnect();
    }, [componentRef, observer]);

    return [componentRef, isOutOfBounds];

};
  • useRef 使用される😂) フックのユーザーがコンポーネントに渡すrefを作成するために、我々は観察しています.
  • useState コンポーネントの除外位置に関する情報を格納します
  • useEffect は、コンポーネントがマウントされてアンマウントされたときに観察とクリーンアップを開始するのに使用されます
  • また、私たちはMutationObserver そして、コールバックを通過すると、心配しないでください.内部useEffect 私たちはobserve メソッドMutationObserver コンポーネントrefが更新されたときに作成されます.これは、観測者がDOM要素/コンポーネントを変更して監視/監視を開始するよう指示するものです.最後にuseEffect 我々は、単にdisconnect メソッドMutationObserver クリーンアップのコンポーネントを見て停止するには(我々は迷走オブザーバーを実行したくない).
    最後に、フックの戻り値を定義し、典型的なフックのファッションでは、配列を返しています.最初の項目は、ユーザがコンポーネントに渡すコンポーネントのrefであり、2番目の要素は、コンポーネントがどれだけ離れているかを詳細に説明するオブジェクトです.

    コールバック設定


    では、MutationObserver , これはすべての仕事をするために行くつもりです.私はフックコードの残りの部分を上から繰り返すつもりはありませんが、このコードはフック関数の範囲内でなければなりません.
    const mutationObserverCallback = (mutationRecord, observer) => {
        if (componentRef.current) {
          const rect = componentRef.current.getBoundingClientRect();
          const windowWidth = Math.min(document.documentElement.clientWidth, window.innerWidth);
          const windowHeight = Math.min(document.documentElement.clientHeight, window.innerHeight);
          let directions = {
            top: 0,
            bottom: 0,
            left: 0,
            right: 0
          };
    
          if (rect.top < 0) {
            directions.top = Math.abs(0 - rect.top);
          } 
    
          if (rect.bottom > windowHeight) {
            directions.bottom = Math.abs(windowHeight - rect.bottom);
          }
    
          if (rect.left < 0) {
            directions.left = Math.abs(0 - rect.left);
          }
    
          if (rect.right > windowWidth) {
            directions.right = Math.abs(windowWidth - rect.right);
          }
    
          if (isOutOfBounds.top !== directions.top || isOutOfBounds.bottom !== directions.bottom || isOutOfBounds.left !== directions.left || isOutOfBounds.right !== directions.right) {
            setIsOutOfBounds(directions);
          }
        }
      }
    
    フィル💨 それは多くのコードです、私に説明させてください!
  • rect 基本的に我々が見ているコンポーネントの位置です.上部、右、左、および下部は、ビューポートのそれらの様々な側面からのコンポーネントの距離です.( Mozilla Docs )
  • windowWidth and windowHeight かなり自明です
  • これらの変数を定義した後に、if文の中のいくつかの単純な論理を通って、コンポーネントの様々な辺のビューポートからのピクセルの量を取得します.
    最後に、現在の境界と新しい設定のプロパティの比較を行います.

    フックの使用時間🥳


    実際に全く簡単なことは、フックのようにフックをインポートする必要があります.
    import { useOutOfBounds } from './path-to-hook'
    
    それからフックを呼び出します(フックから返された配列を覚えておいてください.
    const [componentRef, outOfBounds] = useOutOfBounds();
    

    デモ


    これは、このフックを使用してCRAのアプリで作ったクイックデモのGIFです.テキストがビューポートからわずかに動かされるとき、あなたは境界オブジェクトの外がコンソールに記録されるのを見ます.

    我々は完了です!🎉


    私たちはカスタムフックを作った!それがそうするあなたの最初であるならば、Congrats!うまくいけないならば、あなたは若干の将来のプロジェクトでこのフックを使うことができます!