<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>懒加载</title>
<style>
img {
width: 600px;
height: 450px;
}
</style>
<script src="./lazyLoad.js"></script>
</head>
<body>
<img src="" data-src="./imgs/css3.png">
<img src="" data-src="./imgs/css3.png">
<img src="" data-src="./imgs/css3.png">
<img src="" data-src="./imgs/css3.png">
<img src="" data-src="./imgs/css3.png">
<img src="" data-src="./imgs/css3.png">
<img src="" data-src="./imgs/css3.png">
<img src="" data-src="./imgs/css3.png">
</body>
</html>
lazyLoad.js
/**
* 在使用一下懒加载的方式之前,图片要设置宽高,不设置宽高,会判断所有图片都在可视区域内
* 整个懒加载方案还需要一下几点的优化:
* 1. 可视区域的的元素,目前是浏览器可视窗口,无法对可视区域进行判断
* 2. 事件监听一直存在,目前没有做销毁,考虑在图片全部加载完成后,销毁会导致后续增加的图片就无法触发懒加载
* 3. 对于元素的选中,虽然是通过标签名+属性值,但后续还可进行优化,从而获取更加精准的懒加载目标
*/
window.onload = function() {
var imgList = []
var leftInterval = 100 * window.devicePixelRatio // 横向阈值
var heightInterval = 200 * window.devicePixelRatio // 纵向阈值
var throttleTime = 1000 // 节流时间
var debounceTime = 1000 // 防抖时间
var errorSrc = './imgs/wallhaven-1jxw53.jpg' // 图片加载失败的图片
// 判断图片是否出现出现在可视区域的首选方案
var observer = new IntersectionObserver(function(entries) {
entries.forEach(item => {
if (item.isIntersecting) {
// 只处理src=""和没有src属性的图片
if (item.target.src !== null) {
handleImgSrc(item.target)
observer.unobserve(item.target)
}
}
})
})
// 给图片添加src,并处理onerror事件
function handleImgSrc(dom) {
// 已经显示的图片不再处理
if (dom.getAttribute('src')) return
const dataSrc = dom.getAttribute('data-src')
if (dataSrc) {
dom.src = dataSrc
}
dom.onerror = () => {
dom.src = errorSrc
}
}
// 节流函数
function throttle(callback, delay) {
let timer = null
let _this = this
return function(...args) {
if (!timer) {
timer = setTimeout(() => {
callback.call(_this, args)
timer = null
}, delay)
}
}
}
// 防抖函数
function debounce(callback, delay) {
let timer = null
let _this = this
return function(...args) {
clearTimeout(timer)
timer = setTimeout(() => {
callback.call(_this, args)
}, delay)
}
}
// 判断图片是否出现再可是区域额兼容性写法
function isIn(dom) {
const clientWidth = window.innerWidth,
clienHeight = window.innerHeight,
bound = dom.getBoundingClientRect()
return (bound.top < clienHeight + heightInterval && bound.left < clientWidth + leftInterval)
}
// 懒加载
function lazyLoad() {
imgList.forEach(item => {
if (IntersectionObserver) {
observer.observe(item)
} else if (isIn(item)) {
handleImgSrc(item)
}
})
}
// 根据标签name和属性,获取相应的dom
function getElementsByTagNameAndAttribute(tag, attribute) {
const allTags = document.getElementsByTagName(tag)
return Array.from(allTags).filter(item => {
return item.getAttribute(attribute)
})
}
// 这里用一个变量记录,后期优化可以方便清除监听,
// 目前没有设置清楚监听,考虑第一轮图片加载完后,将监听清除后,后面第二轮的图片就无法实现懒加载的功能
var throttleLazy = throttle(lazyLoad, 1000)
var debounceLazy = debounce(lazyLoad, 1000)
function init() {
imgList = getElementsByTagNameAndAttribute('img', 'data-src')
lazyLoad()
window.addEventListener('scroll', throttleLazy, throttleTime)
window.addEventListener('resize', debounceLazy, debounceTime)
}
init()
}