图片懒加载实现/通过vue指令实现

2021-01-06  本文已影响0人  Raral

1. 通过scroll事件监听

let windowHeight = document.documentElement.clientHeight;
        let imgs = document.getElementsByTagName("img");
        console.log(imgs[1].getBoundingClientRect())
        window.addEventListener('scroll', function() {
            listenerLoad();
        })

        function listenerLoad() {
            Array.prototype.forEach.call(imgs,function(img) {
                let imgTop = img.getBoundingClientRect().top;
                let imgBtm = img.getBoundingClientRect().bottom;
                if(imgTop - windowHeight < 20 && imgBtm > 0) {
                    let realSrc = img.dataset.src;
                    console.log(realSrc)
                    img.setAttribute("src", realSrc);
                    // img.removeAttribute("data-src");
                }
            })

        }

        listenerLoad();

2. 通过 IntersectionObserver 实现

  let windowHeight = document.documentElement.clientHeight;
        let imgs = document.getElementsByTagName("img");
        const options = {
            root: document.body,
            threshold:[0, 0.25, 0.5, 0.75, 1],//交会处
            rootMargin:"0px"//对视口进行收缩和扩张
        }
        // 使用 IntersectionObserver 
        function lazyLoad(img) {
            var io = new IntersectionObserver((entries, observer) => {
                entries.forEach(entry => {
                    if(entry.isIntersecting) {
                        let realSrc = img.dataset.src;
                        img.setAttribute("src", realSrc);
                        observer.disconnect();
                    }
                })

            })
            io.observe(img);

        }

        Array.prototype.forEach.call(imgs, function(img) {
            lazyLoad(img)//每个图片都要进行观察
        })

3. vue指令实现

/**
 * 图片懒加载
 * 背景: 在类电商项目中,往往有大量的图片,如banner广告图,商品图很多
 * 需求:通过一个图片加载指令,只加载浏览器可见区域的图片
 * 思路:
 *      1. 图片懒加载的原理主要是判断当前图片是否到了可视区域这一核心逻辑实现的
 *      2. 拿到所有的图片Dom,遍历每个图片的判断当前图片是否达到了可视范围内
 *      3. 如果到了就设置 src 属性, 否则显示默认图片
 * 图片懒加载有两种方式可以实现
 *      1. srcoll事件监听, 性能有点差,需不停去监听用户的滚动,可以通过节流优化
 *      2. 使用 Intersection Observer 判断图片是否到了可视区域, 但是有浏览器兼容性问题
 */

const lazyLoad = {
    //install方法
    install(Vue,options) {
        console.log("fasdf",options)
        const defaultSrc = options.default;//占位图
        Vue.directive("lazyLoad", {
            bind(el,binding) {//初始化
                lazyLoad.init(el, binding.value,defaultSrc);
            },
            inserted(el) {//第一次插入节点
                if(IntersectionObserver ) {
                    lazyLoad.observe(el);
                }else {
                    lazyLoad.listenerScroll(el);
                } 
                // lazyLoad.listenerScroll(el);
            }
        })
        

    },
    //初始化操作
    init(el,val,def) {
        el.setAttribute("data-src", val);//把需要加载的图片放入到自定义属性
        el.setAttribute("src", def);// 把占位图片放入到 真实的src属性
    },

    //通过监听IntersectionObserver 监听el属性
    observe(el) {
        const options = {
            // root: con,
            // threshold:1,//交会处
            // rootMargin:"0px"//对视口进行收缩和扩张
        }
        var io = new IntersectionObserver((entries) => {
            const realSrc = el.dataset.src;
            if(entries[0].isIntersecting) {
                if(realSrc) {
                    el.src = realSrc;
                    el.removeAttribute("data-src");

                }
            }
           
        },options)
        io.observe(el);

    },

    //监听scroll事件
    listenerScroll(el) {
        lazyLoad.load(el);//第一次触发回调函数
        const handler = lazyLoad.throttle(lazyLoad.load, 300);
        window.addEventListener("scroll", () => {
            handler(el);
        })
    },

    //加载真实的图片
    load(el) {
      
       //1. 获取当前图片的偏移高度
       //2. 获取当前滚动区域的偏移高度
       //3. 获取可视的区域
        const windowHeight = document.documentElement.clientHeight;
        const imgTop = el.getBoundingClientRect().top;
        const imgBtm = el.getBoundingClientRect().bottom;
        const realSrc = el.dataset.src;
        console.log(windowHeight, imgTop, imgBtm);
        if(imgTop - windowHeight < 0 && imgBtm > 0) {
            if(realSrc) {
                el.src = realSrc;
                el.removeAttribute("data-src");
            }
        }
    },

    //节流
    throttle(fn,delay) {
        let previous = 0;
        return function() {
            let _this = this;
            let args = arguments;
            let now = new Date().getTime();
            if(now - previous > delay) {
                fn.apply(_this, args);
                previous = now;
            }
        }
    }

}

export default lazyLoad;
上一篇下一篇

猜你喜欢

热点阅读