javascript - lazy - intersectionobserver polyfill
¿Cómo puedo saber la dirección de desplazamiento de IntersectionObserver? (4)
Entonces, ¿cómo sé la dirección de desplazamiento cuando se desencadena el evento?
En el objeto devuelto, la posibilidad más cercana que veo es interactuar con el modo boundingClientRect
de guardar la última posición de desplazamiento, pero no sé si el manejo de boundingClientRect
terminará en problemas de rendimiento.
¿Es posible utilizar el evento de intersección para averiguar la dirección de desplazamiento (arriba / abajo)?
He añadido este fragmento básico, así que si alguien me puede ayudar.
Estaré muy agradecido.
Aquí está el fragmento:
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>
Me gustaría saber esto, así que puedo aplicarlo en el menú de encabezados fijos para mostrarlo / ocultarlo
No sé si el manejo de boundingClientRect terminará en problemas de rendimiento.
MDN indica que IntersectionObserver
no se ejecuta en el hilo principal:
De esta manera, los sitios ya no necesitan hacer nada en el subproceso principal para observar este tipo de intersección de elementos, y el navegador es libre de optimizar la administración de las intersecciones cuando lo considere oportuno.
MDN, "Intersection Observer API"
Podemos calcular la dirección de desplazamiento guardando el valor de IntersectionObserverEntry.boundingClientRect.y
y comparándolo con el valor anterior.
Ejecute el siguiente fragmento de código para un ejemplo:
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>
Si la función de ayuda de thresholdArray
puede confundirlo, crea una matriz que va de 0.0
a 1.0
por la cantidad dada de pasos. Pasar 5
devolverá [0.0, 0.2, 0.4, 0.6, 0.8, 1.0]
.
:)
No creo que esto sea posible con un solo valor de umbral. Podría intentar vigilar la intersectionRatio
que en la mayoría de los casos es algo inferior a 1
cuando el contenedor sale de la ventana gráfica (porque el observador de la intersección dispara de forma asíncrona). Estoy bastante seguro de que también podría ser 1
si el navegador se recupera lo suficientemente rápido. (No probé esto: D)
Pero lo que quizás podría hacer es observar dos umbrales usando varios valores. :)
threshold: [0.9, 1.0]
Si obtienes un evento para el 0.9
primero, está claro que el contenedor entra en la ventana gráfica ...
Espero que esto ayude. :)
Al comparar boundingClientRect
y rootBounds
desde la entry
, puede saber fácilmente si el objetivo está por encima o por debajo de la ventana gráfica.
Durante la callback()
, marca isAbove / isBelow y luego, al final, lo guarda en wasAbove / wasBelow. La próxima vez, si el objetivo está en la ventana gráfica (por ejemplo), puedes verificar si estaba arriba o abajo. Así que ya sabes si viene de arriba o de abajo.
Puedes probar algo como esto:
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;
});
}
Espero que esto ayude.
Mi requerimiento era:
- no hacer nada en scroll-up
- en el desplazamiento hacia abajo, decide si un elemento comenzó a ocultarse en la parte superior de la pantalla
Necesitaba ver información proporcionada por IntersectionObserverEntry
:
- intersectionRatio (debería estar disminuyendo de 1.0)
- boundingClientRect.bottom
- boundingClientRect.height
Así que la devolución de llamada terminó como:
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] });
Ver mi post para los códigos completos.