懒加载与节流
2019-08-24 本文已影响0人
twentyshaw
1. 概念
懒加载也叫延迟加载,指的是在长网页中延迟加载图像,是一种很好优化网页性能的方式。 用户滚动到它们之前,可视区域外的图像不会加载。 这与图像预加载相反,在长网页上使用延迟加载将使网页加载更快。 在某些情况下,它还可以帮助减少服务器负载。
2. 对图片的配置
将图片的地址写在 data-src
里,而不是src里面,方便我们操作它。并且为图片添加class名“lazyload”,标记出需要懒加载的图片。
3. 思路
监听页面的滚动(scroll事件),当页面滚动时遍历图片,判断图片是否在视口内,如果是就加载图片。
4. 代码
4.1. 监听浏览器的scroll事件:
window.addEventListener("scroll",onscroll)
4.2. 判断img是否处于视口:
4.3. 加载img
4.4. 节流
但此时虽然实现了懒加载,但以上的判断和加载会在滚动的时候不断重复调用。为了避免这种情况发生,需要节流:
5. 完整代码
function lazyload(images) {
//将获取到的图片转成数组,也可以写成: Array.from(images)
let imgs = [].slice.call(images || document.querySelectorAll('.lazyload'))
let onscroll = throttle(function() {
if (imgs.length === 0) {
return window.removeEventListener('scroll', onscroll)
}
imgs = imgs.filter(img => img.classList.contains('lazyload'))
imgs.forEach(img => inViewport(img) && loadImage(img))
}, 300)
window.addEventListener('scroll', onscroll)
window.dispatchEvent(new Event('scroll'))
}
function inViewport(img){
let {top, bottom, left, right} = img.getBoundingClientRect()
let vpWidth = document.documentElement.clientWidth
let vpHeight = document.documentElement.clientHeight
return (
(top > 0 && top < vpHeight || bottom > 0 && bottom < vpHeight) &&
(left > 0 && left < vpWidth || right > 0 && right < vpWidth)
)
}
function loadImage(img, callback){
let image = new Image()
image.src = img.dataset.src
image.onload = function(){
img.src = image.src
img.classList.remove("lazyload")
if (typeof callback === "function") callback()
}
}
function throttle(func, wait){
let prev,timer
return function fn(){
let curr = Date.now()
let differ = curr - prev
if (!prev || differ >= wait) {
func()
prev = curr
}else if(differ < wait){
clearTimeout(timer)
timer = setTimeout(func, wait -differ)
}
}
}
6. IntersectionObserver接口
对图片的是否进入视口的观测(第4.2步),也可以通过IntersectionObserver API来实现:
let observer = new IntersectionObserver(function(entries) {
entries.forEach(entry => {
if (entry.intersectionRatio > 0) {
loadImage(entry.target, () => {
observer.unobserve(entry.target)
})
}
})
}, { threshold: 0.01 })
imgs.forEach(img => observer.observe(img))