Studi Kasus API Pengamat titik-temu



Selamat siang teman!

Gambaran


Intersection Observer API (IOA) memungkinkan aplikasi untuk secara asinkron memantau persimpangan elemen (target) dengan induknya (root) atau viewport (viewport). Dengan kata lain, API ini menyediakan panggilan ke fungsi tertentu setiap kali elemen target bersinggungan dengan root atau viewport.

Contoh penggunaan:

  • Pemuatan gambar yang malas atau malas
  • Pengguliran halaman tanpa akhir
  • menerima informasi tentang visibilitas iklan untuk tujuan menghitung biaya tayangan
  • memulai proses atau animasi di bidang penglihatan pengguna


Untuk mulai bekerja dengan IOA, Anda perlu menggunakan konstruktor untuk membuat objek pengamat dengan dua parameter - fungsi dan pengaturan callback:

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

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

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

Pengaturan:

  • root - elemen yang bertindak sebagai viewport untuk target (leluhur dari elemen target atau null untuk viewport)
  • rootMargin - margin di sekitar root (margin di CSS, secara default semua margin adalah 0)
  • threshold - angka atau array angka yang menunjukkan persentase persimpangan target dan root yang dapat diterima

Berikutnya, elemen target dibuat, yang ditonton pengamat:

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

Panggilan balik mengembalikan objek yang berisi catatan perubahan yang telah terjadi dengan elemen target:

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

Jaringan ini penuh dengan informasi tentang teori, tetapi sedikit materi tentang praktik menggunakan IOA. Saya memutuskan untuk mengisi sedikit celah ini.

Contohnya


Pemuatan gambar yang malas (tertunda)


Tugas: mengunggah (menampilkan) gambar saat pengguna menggulir halaman.

Kode:

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

Hasil:


Latar belakang wadah di luar viewport berwarna putih.



Saat Anda melintasi area tampilan setengah, latar berubah menjadi biru langit.

Codepen

→  Github

Penggantian Gambar


Tugas: mengubah gambar placeholder ke aslinya ketika pengguna menggulir halaman.

Kode:

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

Hasil:


Gambar pertama diunggah karena berada di area tampilan. Yang kedua adalah placeholder.



Saat Anda menggulir lebih jauh, placeholder diganti dengan gambar asli.

Codepen

→  Github

Ubah latar belakang wadah


Tugas: untuk mengubah latar belakang wadah saat pengguna menggulir halaman di sana dan kembali.

Kode:

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

Hasil:


Latar belakang wadah berubah dari biru



muda ...



menjadi biru ... menjadi merah muda.

Codepen

→  Github

Bekerja dengan video


Tugas: Jeda video yang sedang diputar dan mulai lagi tergantung pada video yang jatuh ke area tampilan.

Kode:

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

Hasil:



Saat video berada di area tontonan, video diputar.



Segera setelah video melampaui area tontonan lebih dari 40%, pemutarannya jeda. Jika Anda menekan area tampilan> 40% dari video, pemutarannya dilanjutkan.

Codepen

→  Github

Kemajuan Tampilan Halaman


Tugas: menampilkan kemajuan dalam melihat halaman saat pengguna menggulir halaman.

Kode:

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

Hasil:



Halaman baru saja dimuat, jadi kami belum melihat wadah apa pun.



Ketika akhir halaman tercapai, paragraf menampilkan informasi tentang melihat 4 div.

Codepen

→  Github

Pengguliran tanpa akhir


Tugas: mengimplementasikan daftar tanpa akhir.

Kode:

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

Hasil:



Kami memiliki 12 item daftar. Item terakhir berada di luar viewport.



Saat Anda mencoba untuk sampai ke elemen terakhir, elemen baru (terakhir) dibuat yang disembunyikan dari pengguna. Dan seterusnya hingga tak terbatas.

Codepen

→  Github

Mengubah ukuran anak ketika mengubah ukuran orang tua


Tugas: menetapkan ketergantungan ukuran satu elemen pada elemen lainnya.

Kode:

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

Hasil:



Status awal.



Saat mengurangi lebar elemen induk, lebar elemen turunan berkurang. Pada saat yang sama, jarak di antara mereka hampir selalu sama dengan 50px ("hampir" disebabkan oleh implementasi mekanisme terbalik).

Codepen

→  Github

Bekerja dengan animasi


Tugas: menghidupkan objek ketika terlihat.

Kode:

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

Hasil:



Kami melihat bagian kepala Bart. Bart menekan ke sisi kiri area tampilan.



Jika lebih dari 50% Bart jatuh ke area tampilan, ia bergerak ke tengah. Ketika lebih dari 50% Bart meninggalkan area tampilan, ia kembali ke posisi semula.

Codepen

→  Github

Terima kasih atas perhatian Anda.

All Articles