Principio de carga diferida de imagen
El atributo personalizado data-src de la imagen renderizada es la ruta de la imagen real, y se juzga si la imagen está en el área no disponible. Si está en el área no disponible, el valor de la ruta de la imagen real data-src se asigna a la imagen src.
Escenario de aplicación
El escenario de la aplicación de carga diferida está sesgado hacia las solicitudes de recursos de red, lo que resuelve el problema de que el tiempo de respuesta del sitio web es demasiado largo debido a demasiadas solicitudes de recursos de red.
¿Cómo juzgar si la imagen está en el área visible?
1.offsetTop: la altura desde la parte superior del elemento actual hasta la parte superior del elemento principal
2.window.innerHeight: la altura de la ventana visible, excluyendo la barra de herramientas en la parte superior del navegador
3.scrollTop: la distancia entre la parte superior del elemento actual y la parte superior de la ventana, es decir, la altura más allá del área visible
Cuando offsetTop <= window.innerHeight + scrollTop, el elemento está en el área disponible
método uno:
function App() {
const [imgList, setImgList] = useState([])
const [start, setStart] = useState(0)
const [end, setEnd] = useState(10)
useEffect(() => {
let list:any = []
for (let index = 0; index < 10000; index++) {
list.push('/vite.svg')
}
setImgList(list)
},[])
const handleScroll = () => {
let img = document.getElementsByTagName('img')
const viewHeight = window.innerHeight
const scrollTop = document.querySelector('.App')?.scrollTop
const maxViewHeight = viewHeight + scrollTop
let n = 11
for (let i = n; i < img.length; i++) {
if(img[i].offsetTop <= maxViewHeight){
const src = img[i].getAttribute('data-src')
img[i].src = src || ''
}
n = i+1
}
}
return (
<div className="App" onScroll = {handleScroll}>
<div className='box'>
{imgList.map((item,index) => {
if(index >= start && index <= end){
return <img src={item} data-src="" className="logo" alt="Vite logo" key={index}/>
} else {
return <img src="" data-src={item} className="logo" alt="Vite logo" key={index}/>
}
})}
</div>
</div>
)
}
Método dos
const handleScroll = () => {
let img = document.getElementsByTagName('img')
const viewHeight = document.querySelector('.App')?.clientHeight
let n = 11
for (let i = n; i < img.length; i++) {
if(img[i].getBoundingClientRect().top <= viewHeight){
const src = img[i].getAttribute('data-src')
img[i].src = src || ''
}
n = i+1
}
}
método getBoundingClientRect: Element.getBoundingClientRect() - Referencia de la interfaz API web | MDN
metodo tres
import { useState, useEffect, } from 'react'
import reactLogo from './assets/react.svg'
import './App.css'
function App() {
const [imgList, setImgList] = useState( [])
useEffect(() => {
let list:any = []
for (let index = 0; index < 10000; index++) {
list.push('/vite.svg')
}
setImgList(list)
},[])
useEffect(() => {
if(IntersectionObserver){
imgList.length && lazyLoad()
}
},[imgList])
const lazyLoad = () => {
let img = document.getElementsByTagName('img')
let io = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
// 获取当前元素
let curImg = entry.target
console.log(entry);
// 判断是否已经处于可视区域
if (entry.intersectionRatio > 0 && entry.intersectionRatio <= 1) {
curImg.setAttribute('src', curImg.getAttribute('data-src'))
}
})
})
Array.from(img).forEach((element) => {
io.observe(element)
})
}
return (
<div className="App" onScroll = {handleScroll}>
<div className='box'>
{imgList.map((item,index) => {
return <img src="" data-src={item} className="logo" alt="Vite logo" key={index}/>
})}
</div>
</div>
)
}
export default App
Tutorial de la API de IntersectionObserver: blog de Ruan Yifeng