图片的性能优化也是我们经常用到的。实现效果如下:图片在视口的底部出现加载的图片(占位 保证页面不空白),当图片完全显示在视口就将图片加载出来。
原理如下:图片向上移动,会触发两个交叉。一次是进入时,一次完全出去时。这里主要方法是:getBoundingClientRect()获取到可视口的距离。
页面:
<div class="laztImageBox">
<img src="image/loading.png" lazt-image="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603881530968&di=25f67319d28331beda5b78fba1899c63&imgtype=0&src=http%3A%2F%2Fa2.att.hudong.com%2F86%2F10%2F01300000184180121920108394217.jpg"/>
</div>
样式:
body{
height: 1800px;
}
.laztImageBox{
position: absolute;
top: 1000px;
}
.laztImageBox img{
width: 100%;
height: 100%;
}
方法一:传统方式 采用监听图片+节流的方式 (这里测试demo就没有加节流,自行添加哈),缺点:节流减低触发频率,导致可能要多移动一段距离才会及时反应。
let lazyImageBox = document.querySelector('.laztImageBox'),
lazyImage=lazyImageBox.querySelector('img');
const singleLazy = function singleLazy(){
let trueImg = lazyImage.getAttribute('lazt-image')
lazyImage.src = trueImg
lazyImage.onload = () =>{
// 真实图片加载成功
lazyImage.style.opacity = 1
}
lazyImageBox.isload = true
}
// 方法1:缺点无法及时监听会有延迟 (传统方法)
const lazyFunc = function lazyFunc(){
// 防止重复加载
if(lazyImageBox.isload==true){return}
let A = lazyImageBox.getBoundingClientRect().bottom
let B = document.documentElement.clientHeight
if(A<=B){
singleLazy()
}
}
setTimeout(lazyFunc,1000)
window.onscroll = lazyFunc ; //浏览器会在最快的反应时间,监听到scorll事件的触发,从而执行这个方法,这将导致触发频率过高=>做个节流
2.方法二:使用dom监听器 IntersectionObserver:监听一个或多个可视窗口的交叉信息。效果比方法一好用
let lazyImageBox = document.querySelector('.laztImageBox'),
lazyImage=lazyImageBox.querySelector('img')
// 使用dom监听器 IntersectionObserver:监听一个或多个可视窗口的交叉信息
// 方法2
let ob = new IntersectionObserver(change =>{
// chaneg是一个数组,包含所有监听的dom元素和视口的交叉信息
let item = change[0],
{
isIntersecting,
target,
}=item
if(isIntersecting){
// 完全出现在视口中
singleLazy()
ob.unobserve(lazyImageBox);//加载真实图片后,移除对盒子的监听
}
// console.log(item),
},{
threshold:[1] //指定显示的状态触发 例如:0.5一半,1完全,可以写多个触发条件
})
ob.observe(lazyImageBox)//默认监听的时候是去重的
const singleLazy = function singleLazy(){
let trueImg = lazyImage.getAttribute('lazt-image')
lazyImage.src = trueImg
lazyImage.onload = () =>{
// 真实图片加载成功
lazyImage.style.opacity = 1
}
lazyImageBox.isload = true
}
多张图片,进行封装 laztImage.js
(function(){
function LazyImage(options){
options = options || {}
let defaults = {
context:document,
attr:'lazy-image',
threshold:1,
speed:300,
callback:Function.prototype
}
return new LazyImage.prototype.init(Object.assign(defaults,options))
}
LazyImage.prototype={
constructor:LazyImage,
init:function init(config){
// 把信息挂在实例上,其它方法中,基于实例即可获取这些信息
this.config = config
this.imageBoxList = []
// 创建监听器
const oboptions = {threshold:[config.threshold]}
this.ob = new IntersectionObserver(changes =>{
changes.forEach(item =>{
let {
isIntersecting,
target
}= item
if(isIntersecting){
this.singHandle(target)
this.ob.unobserve(target)
}
})
},oboptions)
this.observeAll()
},
// 单张图片的延迟加载
singHandle:function singHadle(imgBox){
console.log(imgBox)
let config = this.config,
imgObj = imgBox.querySelector('img'),
trueImg = imgObj.getAttribute(config.attr);
imgObj.src= trueImg
console.log(trueImg)
imgObj.onload=()=>{
imgObj.style.transition = `opacity${config.speed}ms`
imgObj.style.opacity = 1
// 回调函数->插件的生命周期函数[回调函数&发布订阅]
config.callback.call(this,imgObj)
}
},
// 监听需要的DOM元素
observeAll(){
let config = this.config,
allImages = config.context.querySelectorAll(`img[${config.attr}]`);
[].forEach.call(allImages,(item) =>{
let imageBox = item.parentNode;
// if(this.refresh() && this.imageBoxList.include(imageBox)){return}
this.imageBoxList.push(imageBox)
console.log(this.imageBoxList)
this.ob.observe(imageBox)
})
},
refresh:function refresh(){
// this.ob.observe(true)
return true
}
}
LazyImage.prototype.init.prototype = LazyImage.prototype;
if(typeof window!=='undefind'){
window.LazyImage = LazyImage
}
if(typeof module==='object'&& typeof module.exports === 'obejct'){
module.exports = LazyImage
}
})()
调用:
//test.html
<script src="laztImage.js"></script>
<div class="laztImageBox">
<div>
<img src="image/loading.png" lazt-image="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603881530968&di=25f67319d28331beda5b78fba1899c63&imgtype=0&src=http%3A%2F%2Fa2.att.hudong.com%2F86%2F10%2F01300000184180121920108394217.jpg"/>
</div>
<div>
<img src="image/loading.png" lazt-image="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603881530968&di=25f67319d28331beda5b78fba1899c63&imgtype=0&src=http%3A%2F%2Fa2.att.hudong.com%2F86%2F10%2F01300000184180121920108394217.jpg"/>
</div>
</div>
<script>
var laztImageBox = document.querySelector('.laztImageBox')
LazyImage({context:laztImageBox,attr:"lazt-image"})
</script>