web-dev-qa-db-ja.com

IntersectionObserverのスクロール方向を知るにはどうすればよいですか?

それで、イベントがトリガーされたときにスクロール方向を知るにはどうすればよいですか?

返されたオブジェクトで最も近い可能性は、boundingClientRect種類の最後のスクロール位置の保存と対話することですが、boundingClientRectの処理がパフォーマンスの問題で終わるかどうかはわかりません。

交差イベントを使用してスクロール方向(上/下)を把握することは可能ですか?

この基本スニペットを追加したので、誰かが私を助けてくれれば。
とても感謝します。

以下がスニペットです。

var options = {
  rootMargin: '0px',
  threshold: 1.0
}

function callback(entries, observer) { 
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      console.log('entry', entry);
    }
  });
};

var elementToObserve = document.querySelector('#element');
var observer = new IntersectionObserver(callback, options);

observer.observe(elementToObserve);
#element {
  margin: 1500px auto;
  width: 150px;
  height: 150px;
  background: #ccc;
  color: white;
  font-family: sans-serif;
  font-weight: 100;
  font-size: 25px;
  text-align: center;
  line-height: 150px;
}
<div id="element">Observed</div>

これを知りたいので、これを固定ヘッダーメニューに適用して表示/非表示にすることができます

23
Jose Paredes

BoundingClientRectの処理でパフォーマンスの問題が発生するかどうかはわかりません。

MDNは、IntersectionObserverがメインスレッドで実行されないことを示しています。

このように、サイトはこの種の要素の交差を監視するためにメインスレッドで何もする必要がなくなり、ブラウザは適切と思われる交差の管理を自由に最適化できます。

MDN、「交差点オブザーバーAPI」

IntersectionObserverEntry.boundingClientRect.y の値を保存してスクロール方向を計算し、それを前の値と比較できます。

例として次のスニペットを実行します。

const state = document.querySelector('.observer__state')
const target = document.querySelector('.observer__target')

const thresholdArray = steps => Array(steps + 1)
 .fill(0)
 .map((_, index) => index / steps || 0)

let previousY = 0
let previousRatio = 0

const handleIntersect = entries => {
  entries.forEach(entry => {
    const currentY = entry.boundingClientRect.y
    const currentRatio = entry.intersectionRatio
    const isIntersecting = entry.isIntersecting

    // Scrolling down/up
    if (currentY < previousY) {
      if (currentRatio > previousRatio && isIntersecting) {
        state.textContent ="Scrolling down enter"
      } else {
        state.textContent ="Scrolling down leave"
      }
    } else if (currentY > previousY && isIntersecting) {
      if (currentRatio < previousRatio) {
        state.textContent ="Scrolling up leave"
      } else {
        state.textContent ="Scrolling up enter"
      }
    }

    previousY = currentY
    previousRatio = currentRatio
  })
}

const observer = new IntersectionObserver(handleIntersect, {
  threshold: thresholdArray(20),
})

observer.observe(target)
html,
body {
  margin: 0;
}

.observer__target {
  position: relative;
  width: 100%;
  height: 350px;
  margin: 1500px 0;
  background: rebeccapurple;
}

.observer__state {
  position: fixed;
  top: 1em;
  left: 1em;
  color: #111;
  font: 400 1.125em/1.5 sans-serif;
  background: #fff;
}
<div class="observer__target"></div>
<span class="observer__state"></span>

thresholdArrayヘルパー関数が混乱する可能性がある場合は、0.0から1.0までの範囲の配列を、指定されたステップ数だけ作成します。 5を渡すと、[0.0, 0.2, 0.4, 0.6, 0.8, 1.0]が返されます。

12
Jason

boundingClientRectrootBoundsentryを比較すると、ターゲットがビューポートの上か下かを簡単に知ることができます。

callback()中にisAbove/isBelowをチェックし、最後にwasAbove/wasBelowに保存します。次回、ターゲットがビューポートに来る場合(たとえば)、それが上か下かを確認できます。したがって、上から来るのか下から来るのかがわかります。

次のようなものを試すことができます:

var wasAbove = false;

function callback(entries, observer) {
    entries.forEach(entry => {
        const isAbove = entry.boundingClientRect.y < entry.rootBounds.y;

        if (entry.isIntersecting) {
            if (wasAbove) {
                // Comes from top
            }
        }

        wasAbove = isAbove;
    });
}

お役に立てれば。

6
thierrymichel

:)

これは単一のしきい値では不可能だと思います。コンテナがビューポートを離れるとき、ほとんどの場合1の下にあるintersectionRatioに注意してみてください(交差点オブザーバーが非同期を起動するため)。ブラウザがすぐに追いつく場合でも、1になる可能性があると確信しています。 (私はこれをテストしませんでした:D)

しかし、おそらくできることは、いくつかの値を使用して2つのしきい値を観察することです。 :)

threshold: [0.9, 1.0]

0.9のイベントを最初に取得した場合、コンテナがビューポートに入ることは明らかです...

お役に立てれば。 :)

2
stefan judis

私の要件は:

  • スクロールアップ時に何もしません
  • スクロールダウンで、要素が画面上部から非表示になり始めたかどうかを判断します

IntersectionObserverEntryから提供されるいくつかの情報を確認する必要がありました。

  • intersectionRatio(1.0から減少するはずです)
  • boundingClientRect.bottom
  • boundingClientRect.height

そのため、コールバックは次のようになりました。

intersectionObserver = new IntersectionObserver(function(entries) {
  const entry = entries[0]; // observe one element
  const currentRatio = intersectionRatio;
  const newRatio = entry.intersectionRatio;
  const boundingClientRect = entry.boundingClientRect;
  const scrollingDown = currentRatio !== undefined && 
    newRatio < currentRatio &&
    boundingClientRect.bottom < boundingClientRect.height;

  intersectionRatio = newRatio;

  if (scrollingDown) {
    // it's scrolling down and observed image started to hide.
    // so do something...
  }

  console.log(entry);
}, { threshold: [0, 0.25, 0.5, 0.75, 1] });

完全なコードについては my post をご覧ください。

1
bob