当访问一个页面的时候,只有当图片出现在浏览器的可视区域内时,才设置图片正真的路径,让图片显示出来。这就是图片懒加载。
- 首先在
html
中设置data-src
属性,其次页面滚动时,图片在可视区域内才去加载,有三个函数,滚动函数,判断是否再可视区,图片真正加载 - 滚动函数
function onscroll() {
if (imgs.length === 0) {
return window.removeEventListener('scroll', onscroll) // 无图片则取消监听
}
imgs = imgs.filter(img => img.classList.contains('lazyload'))
imgs.forEach(img => {
inViewport(img) && loadImage(img)
})
}
- 判断是否在可视区
function inViewport(img) {
let { top,right,left, bottom } = 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) {
let image = new Image()
image.src = img.dataset.src
image.onload = function () {
img.src = image.src
img.classList.remove('lazyload') // 已经加载过就不再加载,上面有过滤
}
}
- 一个小bug,首屏时,在页面不滚动的时候,图片位置显示空白/占位图,可以用事件派发主动触发一次
window.dispatchEvent(new Event('scroll'))
此时,已经完成一半了。
由于一旦滚动便会监听,判断,加载图片,所以以上三个方法调用会非常频繁,影响性能,甚至如果有些重操作,在滚动的时候会出现卡顿的体验。为此,就有了下面的节流
节流
- 有些现成的库提供了方法,如:underscord.js中_.throttle(function(){},wait),返回一个新的函数,该函数调用之间最少是wait的间隔:如图,在滚动的时,1s内触发2次
- 自己实现一个throttle
function throttle(func,wait){ // 节流函数
let prev ,timer
return function fn(){
let curr = Date.now()
let diff = curr - prev
if(!prev || diff >= wait){
func()
prev = curr
}else if(diff < wait){
clearTimeout(timer)
timer = setTimeout(func,wait-diff)
}
}
}
- 新的API
Intersection Observer
很简洁的实现了懒加载
let observer = new IntersectionObserver(function (entries) {
entries.forEach(entry => {
if (entry.intersectionRatio > 0) {
loadImage(entry.target, () => {
observer.unobserve(entry.target)
})
}
})
}, {
threshold: 0.01
})
img.forEach(img => observer.observe(img))
- 此时的
loadImage
需要有个回调函数
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() // 只加此句判断
}
}
后记
因为用到了新的函数getBoundingClientRect()
,为了扩展知识,将其他的可视区范围的相关函数罗列下
屏幕可视窗口大小
**原生方法**:
window.innerHeight 标准浏览器及IE9+ ||
document.documentElement.clientHeight 标准浏览器及低版本IE标准模式 ||document.body.clientHeight 低版本混杂模式
**jQuery方法**:
$(window).height();
浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离:
**原生方法**:
window.pagYoffset 标准浏览器及IE9+ ||
document.documentElement.scrollTop 兼容ie低版本的标准模式 ||
document.body.scrollTop 兼容混杂模式;
**jQuery方法**:
$(document).scrollTop();
获取元素的尺寸
$(0).width() = $(0).style.width;
$(0).innerWidth() = $(0).style.width+o.style.padding;
$(0).outerWidth() = $(0).offsetWidth = $(0).style.width+o.style.padding+o.style.border;
$(0).outerWidth(true) = $(0).style.width+o.style.padding+o.style.border+o.style.margin;