面试之关于懒加载的知识点(很棒)

158 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情

喜欢就点个赞吧🎈😊

🎉 前言

关于懒加载的几种常用的方法,以及在常用方法中使用的API接口的知识点讲解。 图片懒加载的本质是将img的src属性改变为data-src的形式,这样图片就不会再去发送请求获取数据,只有在特定的情况下以Attributed属性通过getAttribute和setAttribute进行设置。

🎉 深入剖析

🎇第一种滚动监听的方式

通过监视视口和滚动条的距离进行判断。其中用到的接口有: 1.获取视口的大小的:

  • innerWidth 和 innerHeight(IE9)
  • document.documentElement.clientHeight和document.documentElement.clientWidth(IE8)
  • document.body.clientWidth 和 document.body. clientHeight(IE6)

IE9和IE8需要在标准模式才有效,如果是混杂模式需要用到IE6
2.获取滚动跳的距离这里也是分为了不同的IE的版本。

  • window.pageYOffset
  • document.documentElement.scrollTop
  • document.body.scrollTop

image.png

3.获取图片距离内容的顶部的距离

  • offsetTOp

image.png

var pageWidth = window.innerWidth, pageHeight = window.innerHeight;  
if (typeof pageWidth != "number"){  
//pageWidth的值不是数值,说明没有innerwidth属性
 if (document.compatMode == "CSS1Compat"){ 
 //标准模式
 pageWidth = document.documentElement.clientWidth; 
 pageHeight = document.documentElement.clientHeight; 
 } else { 
 //混在模式
 pageWidth = document.body.clientWidth; 
 pageHeight = document.body.clientHeight; 
 } 
}

这里将展示在获取了img的图片之后的获取相关数据以及判断图片是否在视口中的过程,其中声明了一个节流的函数,这是因为在我转动鼠标的滚轮之后,出发的scrool的事件太频繁,消耗的资源较多。

 let imgs = document.getElementsByTagName('img')
        // 1. 一上来立即执行一次
        fn()
        // 2. 监听滚动事件
        window.onscroll = lazyload(fn, true)
        function fn() {
            // 获取视口高度和内容的偏移量
            let clietH = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
            var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
            //console.log(clietH, scrollTop);
            for (let i = 0; i < imgs.length; i++) {
                let x = scrollTop + clietH - imgs[i].offsetTop //当内容的偏移量+视口高度>图片距离内容顶部的偏移量时,说明图片在视口内
                if (x > 0) {
                var data_src = imgs[i].getAttribute('data-src')
                    imgs[i].setAttribute("src", data_src); //从dataurl中取出真实的图片地址赋值给url
                }
            }
        }
          // 函数节流
        function lazyload(fn, immediate) {
            let timer = null
            return function () {
                let context = this;
                if (!timer) {
                    timer = setTimeout(() => {
                        fn.apply(this)
                        timer = null
                    }, 200)
                }
            }
        }

🎇第二种监听Scroll事件的方式

这里是利用了getBoundingClientRect()这个可以获得相关元素相对于浏览器窗口的距离,返回一个矩阵对象,此刻就等于img元素调用自己的getClientRects()方法返回的一个矩形对象,并且拥有left, top, right, bottom, x, y, width, 和 height这几个以像素为单位的只读属性用于描述整个边框。除了width 和 height 以外的属性是始终相对于视图窗口的左上角来计算的。当滚动位置发生了改变,top和left属性值就会随之立即发生变化(因此,它们的值是相对于视口的,而不是绝对的)。如果你需要获得相对于整个网页左上角定位的属性值,那么只要给top、left属性值加上当前的滚动位置(通过 window.scrollX 和 window.scrollY),这样就可以获取与当前的滚动位置无关的值。这个相比于第一种方法,就按少了对于滚动的距离的计算,直接获得当前的窗口大小和元素的距离窗口顶部的位置。

image.png

 let imgs = document.getElementsByTagName('img')
        // 1. 一上来立即执行一次
        fn()
        // 2. 监听滚动事件
        window.onscroll = lazyload(fn, true)
        function fn() {
            // 获取视口高度和内容的偏移量
            let offsetHeight = window.innerHeight || document.documentElement.clientHeight
            Array.from(imgs).forEach((item, index) => {
                let oBounding = item.getBoundingClientRect() //返回一个矩形对象,包含上下左右的偏移值
                console.log(index, oBounding.top, offsetHeight);
                if (0 <= oBounding.top && oBounding.top <= offsetHeight) {
                    item.setAttribute('src', item.getAttribute('data-src'))
                }
            })
        }
        // 函数节流
        function lazyload(fn, immediate) {
            let timer = null
            return function () {
                let context = this;
                if (!timer) {
                    timer = setTimeout(() => {
                        fn.apply(this)
                        timer = null
                    }, 200)
                }
            }
        }

🎇第三种 IntersectionObserver事件的方式

IntersectionObserver它是浏览器提供的针对特定元素与视口的交叉之间的监视,如果被监视的元素进入视口就会有监视的触发,并且进行处理。IntersectionObserver但是它需要进行实例化,它本身是一个构造函数的存在。这样就会解决在经行滚动事件是经常被触发的响应事件,和之前两种方法的节流函数是一个意思。

const images = document.querySelectorAll("img");

// 传给IntersectionObserver的回调函数
// 在目标元素能看见时触发一次,目标元素看不见了时再触发一次
const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const image = entry.target;
      const data_src = image.getAttribute("data-src");
      image.setAttribute("src", data_src);
      // 图片被加载后取消观察
      observer.unobserve(image);
    }
  });
});

images.forEach(image => {
  observer.observe(image);
});

🎇第四种直接在img标签上使用loading=“lazy”即可

这个方法的具有搞得浏览器的支持性,不能适配所有的浏览器。

<img src="lazy.jpg" loading="lazy" />

🎉 总结

图片的懒加载是大多数的电商使用的技术,这样就可以避免没必要的流量的浪费,并且能够给用户更好的体验。