图片懒加载(IntersectionObserver)

图片的性能优化也是我们经常用到的。实现效果如下:图片在视口的底部出现加载的图片(占位 保证页面不空白),当图片完全显示在视口就将图片加载出来。

原理如下:图片向上移动,会触发两个交叉。一次是进入时,一次完全出去时。这里主要方法是: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>

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值