Bom dia amigosVisão geral
A API Intersection Observer (IOA) permite que um aplicativo observe de forma assíncrona a interseção de um elemento (destino) com seu pai (raiz) ou viewport (viewport). Em outras palavras, essa API fornece uma chamada para uma função específica sempre que o elemento de destino se cruza com a raiz ou a viewport.Exemplos de uso:- Carregamento preguiçoso ou preguiçoso de imagens
- rolagem de páginas sem fim
- receber informações sobre a visibilidade da publicidade com o objetivo de calcular o custo das impressões
- iniciar um processo ou animação no campo de visão do usuário
Para começar a trabalhar com o IOA, você precisa usar o construtor para criar um objeto observador com dois parâmetros - uma função de retorno de chamada e configurações:
let options = {
root: document.querySelector('.scroll-list'),
rootMargin: '5px',
threshold: 0.5
}
let callback = function(entries, observer){
...
}
let observer = new IntersectionObserver(callback, options)
Definições:- root - um elemento que atua como uma viewport para o destino (ancestral do elemento de destino ou nulo para a viewport)
- rootMargin - margens em torno da raiz (margem em CSS, por padrão todas as margens são 0)
- threshold - um número ou uma matriz de números indicando a porcentagem aceitável de interseção de destino e raiz
Em seguida, o elemento de destino é criado, que o observador observa:let target = document.querySelector('.list-item')
observer.observe(target)
A chamada de retorno de chamada retorna um objeto que contém registros de alterações que ocorreram com o elemento de destino:let callback = (entries, observer) => {
entries.forEach(entry => {
})
}
A rede está cheia de informações sobre a teoria, mas bastante material sobre a prática do uso de IOA. Decidi preencher um pouco essa lacuna.Exemplos
Carregamento de imagem lenta (atrasada)
Tarefa: carregue (mostre) imagens enquanto o usuário rola a página.O 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: o
plano de fundo do contêiner fora da janela de exibição é branco.
Quando você cruza a área de visualização pela metade, o fundo muda para azul celeste.→ Codepen→ GithubSubstituição de imagem
Tarefa: altere a imagem do espaço reservado para o original quando o usuário rolar a página.O 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:
a primeira imagem é carregada porque está na área de visualização. O segundo é um espaço reservado.
À medida que você avança, o espaço reservado é substituído pela imagem original.→ Codepen→ GithubAlterar plano de fundo do contêiner
Tarefa: alterar o plano de fundo do contêiner quando o usuário rolar a página para lá e para trás.O 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: o
fundo do contêiner muda de azul claro ...
para azul ...
para vermelho claro.→ Codepen→ GithubTrabalhar com vídeo
Tarefa: Pause o vídeo em execução e inicie-o novamente, dependendo do vídeo que caia na área de visualização.O 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:
enquanto o vídeo está na área de visualização, ele é reproduzido.
Assim que o vídeo ultrapassa a área de visualização em mais de 40%, sua reprodução é interrompida. Se você atingir a área de visualização> 40% do vídeo, a reprodução será retomada.→ Codepen→ GithubProgresso da exibição da página
Tarefa: mostra o progresso da exibição da página enquanto o usuário rola a página.O 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: a
página acabou de ser carregada, portanto ainda não examinamos nenhum contêiner.
Quando o final da página é alcançado, o parágrafo exibe informações sobre a exibição de 4 divs.→ Codepen→ GithubRolagem sem fim
Tarefa: implemente uma lista interminável.O 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:
temos 12 itens de lista. O último item está fora da janela atual.
Quando você tenta chegar ao último elemento, um novo (último) elemento é criado, oculto ao usuário. E assim por diante até o infinito.→ Codepen→ GithubRedimensionando um filho ao redimensionar um pai
Tarefa: estabelecer a dependência do tamanho de um elemento em outro.O 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.
Ao reduzir a largura do elemento pai, a largura do elemento filho diminui. Ao mesmo tempo, a distância entre eles quase sempre é igual a 50px ("quase" é devido à implementação do mecanismo inverso).→ Codepen→ GithubTrabalhar com animação
Tarefa: animar um objeto quando estiver visível.O 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 da cabeça de Bart. Bart pressionou para o lado esquerdo da área de visualização.
Se mais de 50% de Bart cair na área de visualização, ele se moverá para o meio. Quando mais de 50% de Bart sai da área de visualização, ele volta à sua posição inicial.→ Codepen→ GithubObrigado por sua atenção.