¡Buen dia amigos!Visión general
La API de Intersection Observer (IOA) permite que una aplicación observe asincrónicamente la intersección de un elemento (destino) con su elemento primario (raíz) o ventana gráfica (ventana gráfica). En otras palabras, esta API proporciona una llamada a una función específica cada vez que el elemento de destino se cruza con la raíz o ventana gráfica.Ejemplos de uso:- Carga perezosa o perezosa de imágenes
- desplazamiento de página sin fin
- recibir información sobre la visibilidad de la publicidad con el fin de calcular el costo de las impresiones
- iniciar un proceso o animación en el campo de visión del usuario
Para comenzar a trabajar con IOA, debe usar el constructor para crear un objeto observador con dos parámetros: una función de devolución de llamada y configuraciones:
let options = {
root: document.querySelector('.scroll-list'),
rootMargin: '5px',
threshold: 0.5
}
let callback = function(entries, observer){
...
}
let observer = new IntersectionObserver(callback, options)
Configuraciones:- root: un elemento que actúa como una ventana gráfica para el objetivo (ancestro del elemento objetivo o nulo para la ventana gráfica)
- rootMargin: márgenes alrededor de la raíz (margen en CSS, por defecto todos los márgenes son 0)
- umbral: un número o una matriz de números que indican el porcentaje aceptable de intersección del objetivo y la raíz
A continuación, se crea el elemento objetivo, que el observador observa:let target = document.querySelector('.list-item')
observer.observe(target)
La llamada de devolución de llamada devuelve un objeto que contiene registros de cambios que se han producido con el elemento de destino:let callback = (entries, observer) => {
entries.forEach(entry => {
})
}
La red está llena de información sobre teoría, pero bastante material sobre la práctica de usar IOA. Decidí llenar este vacío un poco.Ejemplos
Carga de imagen perezosa (demorada)
Tarea: cargar (mostrar) imágenes a medida que el usuario se desplaza por la página.El código:
window.onload = () => {
const options = {
root: null,
rootMargin: '0px',
threshold: 0.5
}
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const lazyImg = entry.target
console.log(lazyImg)
lazyImg.style.background = 'deepskyblue'
observer.unobserve(lazyImg)
}
})
}, options)
const arr = document.querySelectorAll('img')
arr.forEach(i => {
observer.observe(i)
})
}
Resultado: el
fondo del contenedor fuera de la ventana gráfica es blanco.
Cuando cruza el área de visualización a la mitad, el fondo cambia a azul cielo.→ Codepen→ GithubReemplazo de imagen
Tarea: cambie la imagen del marcador de posición al original cuando el usuario se desplaza por la página.El código:window.onload = () => {
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log(entry)
entry.target.src = entry.target.dataset.src
observer.unobserve(entry.target)
}
})
}, { threshold: 0.5 })
document.querySelectorAll('img').forEach(img => observer.observe(img))
}
Resultado:
la primera imagen se carga porque está en el área de visualización. El segundo es el marcador de posición.
A medida que avanza, el marcador de posición se reemplaza con la imagen original.→ Codepen→ GithubCambiar fondo de contenedor
Tarea: para cambiar el fondo del contenedor cuando el usuario desplaza la página hacia allí y hacia atrás.El código:window.addEventListener('load', event => {
let box = document.querySelector('div')
let prevRatio = 0.0
let observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
let curRatio = entry.intersectionRatio
curRatio > prevRatio ? entry.target.style.background = `rgba(40,40,190,${curRatio})` : entry.target.style.background = `rgba(190,40,40,${curRatio})`
prevRatio = curRatio
})
}, {
threshold: buildThresholdList()
})
observer.observe(box)
function buildThresholdList() {
let thresholds = []
let steps = 20
for (let i = 1.0; i <= steps; i++) {
let ratio = i / steps
thresholds.push(ratio)
}
return thresholds
}
})
Resultado: el
fondo del contenedor cambia de azul claro ...
a azul ...
a rojo claro.→ Codepen→ GithubTrabajar con video
Tarea: Pause el video en ejecución y comience nuevamente de acuerdo con el video que cae en el área de visualización.El código:window.onload = () => {
let video = document.querySelector('video')
let observer = new IntersectionObserver(() => {
if (!video.paused) {
video.pause()
} else if(video.currentTime != 0) {
video.play()
}
}, { threshold: 0.4 })
observer.observe(video)
}
Resultado:
mientras el video está en el área de visualización, se reproduce.
Tan pronto como el video va más allá del área de visualización en más del 40%, su reproducción se detiene. Si llega al área de visualización> 40% del video, se reanuda su reproducción.→ Codepen→ GithubProgreso de vista de página
Tarea: muestra el progreso de la visualización de la página a medida que el usuario se desplaza por la página.El código:
let p = document.querySelector('p')
let n = 0
let observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if(entry.isIntersecting){
p.textContent = `${n++} div viewed`
observer.unobserve(entry.target)
}
})
}, {threshold: 0.9})
document.querySelectorAll('div').forEach(div => observer.observe(div))
Resultado: la
página se acaba de cargar, por lo que aún no hemos examinado ningún contenedor.
Cuando se llega al final de la página, el párrafo muestra información sobre cómo ver 4 divs.→ Codepen→ GithubDesplazamiento sin fin
Tarea: implementar una lista interminable.El código:let ul = document.querySelector('ul')
let n = 1
function createLi(){
li = document.createElement('li')
li.innerHTML = `${++n} item`
ul.append(li)
}
let observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
createLi()
}
observer.unobserve(entry.target)
observer.observe(document.querySelector('li:last-child'))
})
}, {
threshold: 1
})
observer.observe(document.querySelector('li'))
Resultado:
tenemos 12 artículos de la lista. El último elemento está fuera de la ventana gráfica.
Cuando intenta llegar al último elemento, se crea un nuevo (último) elemento que está oculto para el usuario. Y así hasta el infinito.→ Codepen→ GithubCambiar el tamaño de un niño al cambiar el tamaño de un padre
Tarea: establecer la dependencia del tamaño de un elemento con respecto a otro.El código:
let info = document.querySelector('.info')
let parent = document.querySelector('.parent')
let child = document.querySelector('.child')
child.style.width = parent.offsetWidth - 50 + 'px'
info.textContent = `child width: ${child.offsetWidth}px`
let options = {
root: parent,
threshold: 1
}
let observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if ((entry.target.parentElement.offsetWidth - entry.target.offsetWidth) < 50) {
entry.target.style.width = entry.target.offsetWidth - 50 + 'px'
}
})
}, options)
observer.observe(child)
window.addEventListener('resize', () => {
info.textContent = `child width: ${child.offsetWidth}px`
if ((parent.offsetWidth - child.offsetWidth) > 51) {
child.style.width = child.offsetWidth + 50 + 'px'
}
})
Resultado:
estado inicial.
Al reducir el ancho del elemento primario, el ancho del elemento secundario disminuye. Al mismo tiempo, la distancia entre ellos casi siempre es igual a 50px ("casi" se debe a la implementación del mecanismo inverso).→ Codepen→ GithubTrabajar con animación
Tarea: animar un objeto cuando está visible.El código:
let observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
entry.isIntersecting ? entry.target.classList.replace('to-left', 'to-right') : entry.target.classList.replace('to-right', 'to-left')
})
}, {
threshold: .5
})
observer.observe(document.querySelector('img'))
Resultado:
vemos parte de la cabeza de Bart. Bart presionó el lado izquierdo del área de visualización.
Si más del 50% de Bart cae en el área de visualización, se mueve hacia el medio. Cuando más del 50% de Bart abandona el área de visualización, vuelve a su posición inicial.→ Codepen→ GithubGracias por su atención.