图片懒加载原理
渲染img的自定义属性data-src为真实的图片路径,判断图片是否处于可是区域内,若处于可是区域则给图片src赋值真正的图片路径data-src的值。
应用场景
懒加载的应用场景偏向于网络资源请求,解决网络资源请求过多时,造成的网站响应时间过长的问题。
如何判断图片是否在可视区域?
1.offsetTop:当前元素顶部距离父元素顶部的高度
2.window.innerHeight:可视窗口高度,不包括浏览器顶部工具栏
3.scrollTop:当前元素最顶端与窗口最顶端的距离,即超出可视区域的高度
offsetTop <= window.innerHeight + scrollTop时 元素处于可是区域内
方法一:
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>
)
}
方法二
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
}
}
getBoundingClientRect方法:Element.getBoundingClientRect() - Web API 接口参考 | MDN
方法三
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