Estudios de caso de API de observadores de intersección



¡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 => {
        // entry () - 
        //   entry.boundingClientRect
        //   entry.intersectionRatio
        //   entry.intersectionRect
        //   entry.isIntersecting
        //   entry.rootBounds
        //   entry.target
        //   entry.time
    })
}

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)

    //       img  
    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

→  Github

Reemplazo 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)
                //        "data-src"
                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

→  Github

Cambiar 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')
    // ratio -   
    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)
    
    //    
    //      20 ,   
    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

→  Github

Trabajar 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()
        //      (   > 0)
        } 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

→  Github

Progreso 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')
// n -   
let n = 0

let observer = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
        if(entry.isIntersecting){
            // observer   div
            //       
            //     
            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

→  Github

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

//  ,        
//     
//         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

→  Github

Cambiar 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')
//     50px  
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 => {
        //         50px
        if ((entry.target.parentElement.offsetWidth - entry.target.offsetWidth) < 50) {
            //     50px
            entry.target.style.width = entry.target.offsetWidth - 50 + 'px'
        }
    })
}, options)

observer.observe(child)

//  ,  ,       IOA
//       resize
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

→  Github

Trabajar 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

→  Github

Gracias por su atención.

All Articles