美文网首页
Vue自定义指令实现图片懒加载

Vue自定义指令实现图片懒加载

作者: 欢欣的膜笛 | 来源:发表于2021-05-13 14:55 被阅读0次

什么是图片懒加载

进入页面的时候,只请求可视区域的图片资源

懒加载原理

图片的标签是 img 标签,图片的来源主要是 src 属性,浏览器是否发起加载图片的请求是根据是否有src属性决定的。
所以可以从 img 标签的 src 属性入手,在没进到可视区域的时候,就先不给 img 标签的 src 属性赋值。

懒加载实现

  1. 监听 scroll 事件判断元素是否进入视口
const imgs = [...document.getElementsByTagName('img')];
let n = 0;

lazyload();

function throttle(fn, wait) {
    let timer = null;
    return function (...args) {
        if (!timer) {
            timer = setTimeout(() => {
                timer = null;
                fn.apply(this, args)
            }, wait)
        }
    }
}

function lazyload() {
    var innerHeight = window.innerHeight;
    var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    for (let i = n; i < imgs.length; i++) {
        if (imgs[i].offsetTop < innerHeight + scrollTop) {
            imgs[i].src = imgs[i].getAttribute("data-src");
            n = i + 1;
        }

    }
}
window.addEventListener('scroll', throttle(lazyload, 200));

存在问题:

  • 每次滑动都要执行一次循环,如果有1000多个图片,性能会很差
  • 每次读取 scrollTop 都会引起回流
  • scrollTop 跟 DOM 的嵌套关系有关,应该根据 getboundingclientrect 获取(getBoundingClientRect 用于获取某个元素相对于视窗的位置集合,集合中有top, right, bottom, left 等属性)
  • 滑到最后的时候刷新,会看到所有的图片都加载了

tips:
当 render tree 中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建,称为回流。每个页面至少需要一次回流,就是在页面第一次加载的时候。
当 render tree 中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如 background-color,称为重绘。
注:回流必将引起重绘,而重绘不一定会引起回流。

  1. IntersectionObserver
    IntersectionObserver 接口提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。祖先元素与视窗(viewport,可视视口)被称为根(root)。

    当一个 IntersectionObserver 对象被创建时,其被配置为监听根中一段给定比例的可见区域。一旦 IntersectionObserver 被创建,则无法更改其配置,所以一个给定的观察者对象只能用来监听可见区域的特定变化值;然而,你可以在同一个观察者对象中配置监听多个目标元素。

const imgs = [ ...document.getElementsByTagName('img') ];
// 当监听的元素进入可视范围内的会触发回调
if (IntersectionObserver) {
    // 创建一个 intersection observer
    const lazyImageObserver = new IntersectionObserver((entries, observer) => {
        entries.forEach((entry, index) => {
            let lazyImage = entry.target;
            // 相交率,默认是相对于浏览器视窗
            if (entry.intersectionRatio > 0) {
                lazyImage.src = lazyImage.getAttribute('data-src');
                // 当前图片加载完之后需要去掉监听
                lazyImageObserver.unobserve(lazyImage);
            }

        })
    })
    for (let i = 0; i < imgs.length; i++) {
        lazyImageObserver.observe(imgs[i]);
    }
}
  1. vue自定义指令-懒加载
<img v-lazyload="image">

Vue.directive('lazyload', {
    // 指令的定义
    bind: function(el, binding) {
        let lazyImageObserver = new IntersectionObserver((entries, observer) => {
            entries.forEach((entry, index) => {
                let lazyImage = entry.target;
                // 相交率,默认是相对于浏览器视窗
                if(entry.intersectionRatio > 0) {
                    lazyImage.src = binding.value;
                    // 当前图片加载完之后需要去掉监听
                    lazyImageObserver.unobserve(lazyImage);
                }

            })
        })
        lazyImageObserver.observe(el);
    },
});

相关文章

网友评论

      本文标题:Vue自定义指令实现图片懒加载

      本文链接:https://www.haomeiwen.com/subject/pbbtjltx.html