Études de cas d'API Intersection Observer



Bonjour mes amis!

Aperçu


L'API Intersection Observer (IOA) permet à une application d'observer de manière asynchrone l'intersection d'un élément (cible) avec son parent (racine) ou vue (vue). En d'autres termes, cette API fournit un appel à une fonction spécifique chaque fois que l'élément cible croise la racine ou la fenêtre.

Exemples d'utilisation:

  • Chargement d'images paresseux ou paresseux
  • défilement de page sans fin
  • recevoir des informations sur la visibilité de la publicité dans le but de calculer le coût des impressions
  • démarrer un processus ou une animation dans le champ de vision de l'utilisateur


Pour commencer à travailler avec IOA, vous devez utiliser le constructeur pour créer un objet observateur avec deux paramètres - une fonction de rappel et des paramètres:

// 
let options = {
    root: document.querySelector('.scroll-list'),
    rootMargin: '5px',
    threshold: 0.5
}

//   
let callback = function(entries, observer){
    ...
}

// 
let observer = new IntersectionObserver(callback, options)

Réglages:

  • root - un élément qui agit comme une fenêtre pour la cible (ancêtre de l'élément cible ou null pour la fenêtre)
  • rootMargin - marges autour de root (marge en CSS, par défaut toutes les marges sont 0)
  • seuil - un nombre ou un tableau de nombres indiquant le pourcentage acceptable d'intersection de la cible et de la racine

Ensuite, l'élément cible est créé, que l'observateur observe:

let target = document.querySelector('.list-item')
observer.observe(target)

L'appel de rappel renvoie un objet contenant des enregistrements des modifications qui se sont produites avec l'élément cible:

let callback = (entries, observer) => {
    entries.forEach(entry => {
        // entry () - 
        //   entry.boundingClientRect
        //   entry.intersectionRatio
        //   entry.intersectionRect
        //   entry.isIntersecting
        //   entry.rootBounds
        //   entry.target
        //   entry.time
    })
}

Le réseau regorge d'informations sur la théorie, mais pas mal de matériel sur la pratique de l'utilisation de l'AIO. J'ai décidé de combler un peu cette lacune.

Exemples


Chargement d'image paresseux (retardé)


Tâche: télécharger (afficher) des images lorsque l'utilisateur fait défiler la page.

Le code:

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

Résultat: l'


arrière-plan du conteneur en dehors de la fenêtre est blanc.



Lorsque vous traversez la zone de visualisation de moitié, l'arrière-plan devient bleu ciel.

Codepen

→  Github

Remplacement d'image


Tâche: remplacez l'image d'espace réservé par l'original lorsque l'utilisateur fait défiler la page.

Le code:

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

Résultat:


la première image est téléchargée car elle se trouve dans la zone de visualisation. Le second est l'espace réservé.



Lorsque vous faites défiler la page, l'espace réservé est remplacé par l'image d'origine.

Codepen

→  Github

Changer l'arrière-plan du conteneur


Tâche: changer l'arrière-plan du conteneur lorsque l'utilisateur fait défiler la page vers l'arrière et vers l'arrière.

Le code:

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

Résultat: l'


arrière-plan du conteneur passe du bleu clair ...



au bleu ...



au rouge clair.

Codepen

→  Github

Travailler avec la vidéo


Tâche: suspendez la vidéo en cours et redémarrez-la en fonction de la vidéo tombant dans la zone de visualisation.

Le code:

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

Résultat:



lorsque la vidéo se trouve dans la zone de visualisation, elle est lue.



Dès que la vidéo dépasse de plus de 40% la zone de visualisation, sa lecture s'arrête. Si vous frappez la zone de visualisation> 40% de la vidéo, sa lecture reprend.

Codepen

→  Github

Progression de l'affichage de la page


Tâche: affichez la progression de l'affichage de la page lorsque l'utilisateur fait défiler la page.

Le code:

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

Résultat: la



page vient d'être chargée, nous n'avons donc pas encore regardé de conteneurs.



Lorsque la fin de la page est atteinte, le paragraphe affiche des informations sur l'affichage de 4 divisions.

Codepen

→  Github

Défilement sans fin


Tâche: implémenter une liste sans fin.

Le code:

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'))

Résultat:



nous avons 12 éléments de liste. Le dernier élément est en dehors de la fenêtre.



Lorsque vous essayez d'accéder au dernier élément, un nouvel (dernier) élément est créé qui est caché à l'utilisateur. Et ainsi de suite à l'infini.

Codepen

→  Github

Redimensionner un enfant lors du redimensionnement d'un parent


Tâche: établir la dépendance de la taille d'un élément sur un autre.

Le code:

//      -   
//      
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'
    }
})

Résultat:



état initial.



Lors de la réduction de la largeur de l'élément parent, la largeur de l'élément enfant diminue. Dans le même temps, la distance entre eux est presque toujours égale à 50 px («presque» est due à la mise en œuvre du mécanisme inverse).

Codepen

→  Github

Travailler avec l'animation


Tâche: animer un objet lorsqu'il est visible.

Le code:

//        
//     
//  - 
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'))

Résultat:



on voit une partie de la tête de Bart. Bart appuya sur le côté gauche de la zone d'observation.



Si plus de 50% de Bart tombe dans la zone d'observation, il se déplace vers le milieu. Lorsque plus de 50% de Bart quitte la zone de visualisation, il revient à sa position initiale.

Codepen

→  Github

Merci de votre attention.

All Articles