详解前端性能优化之原生JS实现图片懒加载效果(通过IntersectionObserver内置构造函数实现)

        相信你作为一名用户,使用一款app,在首次打开页面时卡顿超过3秒时就会有退出的想法。所以我们在日常开发中,通常需要使用一些手段实现对性能的优化,来使得页面加载更快,用户体验更好。这其中有许多方式,其中最常用的无非是按需加载了,今天就带大家重点且详细的讲一下原生JS实现的图片懒加载。

图片懒加载的两种实现方式:  

       窗口滚动事件监听图片位置(效果有但不好用)

       IntersectionObserver构造函数(最常用且非常好用)


 注意:这两种方式都需要在JS操作前,将标签中的src属性本该对应的值存在自定义的一个属性(比如data-src)中,因为最开始我们不需要让请求到的图片资源直接加载出来,只是先将其随便存在一个属性当中,在后续的懒加载操作中再将其修改为src。比如以下这种写法:

窗口滚动事件监听图片位置

      实现思路:先获取所有的img标签,然后用window的scroll滚动监听事件对所有image图片进行监听,在浏览器滚动过程中发现如果该图片距离浏览器可视窗口顶部的距离小于浏览器高度,也就是在页面中能看到该图片时触发回调操作,先获取到data-src中的地址,然后把它赋值给真实的src路径使其能够加载出来。具体代码如下:

window.addEventListener("scroll", (e) => { // 为window加入滚动监听事件
  IMGS.forEach(ele => { // 遍历获取到的img标签,为每个都添加监听
      const imgTop = ele.getBoundingClientRect().top; // 获取每一个img图片上方距离浏览器顶部的距离
      // 判断图片上方距离浏览器可视窗口顶部的距离是否小于浏览器高度
      if (imgTop < window.innerHeight) { // 如果小于的话, 说明图片已经在页面中能够被看到, 那么获取
          const data_url = ele.getAttribute("data-src"); // 获取data-src中存放的真实图片url地址
          ele.setAttribute("src", data_url); // 将真实图片url地址给到src路径中
      }
  })
})

这个效果能够虽然能够实现图片的懒加载功能,但它的弊端却又非常多。首先,它是通过滚动监听触发,如果页面顶部有img图片的话在首次加载时如果不去滚动就不会去显示了,还有就是我们在window做监听在图片全部加载完毕后还需要关闭监听事件,这样一想好像有些麻烦了,那么我们就阔以使用第二种方式来解决 --- 通过IntersectionObserver构造函数实现。

 IntersectionObserver构造函数

      IntersectionObserver是浏览器为我们提供的一种构造函数,也就是可以直接拿来使用的,不过前提是浏览器能够支持,部分浏览器版本并不兼容。IntersectionObserver的字面意思就是交叉观察,也就是可以自定义一个目标元素来进行观察,它会和浏览器可视窗口产生交叉区域(也就是当图片在浏览器窗口能够被看到时和不能被看到时),可以在交叉区域发生时来定义我们需要做的事情。

      因为IntersectionObserver是一个构造函数,所以我们需要new一实例,这个构造函数也会接收两个参数,第一个是一个函数,第二个是配置参数,当然这里我们只需要用第一个参数(构造函数)就可以了,这个构造函数也会接收到一个默认参数entries,entries是一个数组,里面会存储着所有被观察的节点相较于浏览器可视窗口的一系列信息,其中entries里面每一个子元素(也就是某个被观察的节点)都有一个 isIntersecting 属性代表该节点是否在浏览器中可以被看到。

如下


看下打印结果:

详解前端性能优化之原生JS实现图片懒加载效果(通过IntersectionObserver内置构造函数实现)_第1张图片


对于Observer实例,我们可以调用 observer() 和 unobserve() 两个方法来进行我们的操作。

其中:

      Observer.observer() 用于加入观察的节点。

      Observer.unobserver() 用于停止观察节点。

     当设置Observer.observer()后,所观察的节点会有两次触发时机。分别是该节点在浏览器可见时和不可见时会触发,我们就可以在这里做我们想做的事情。具体实现思路就是在节点可见时将图片 data-src 中的路径给真实的 src,然后使用Observer.unobserver()来停止观察。

代码如下:

const IMGS = document.querySelectorAll("img"); // 获取所有图片
const callback = entries => { // 设置构造函数中接收到的参数中的操作事项
  entries.forEach(enntry => { // 因为entries里面放着所有被观察的节点,所有需要遍历判断
      if (enntry.isIntersecting) { // 判断当前节点是否在可视区域能被看到
          const image = enntry.target; // 通过事件对象拿到这个元素
          const data_url = image.getAttribute("data-src"); // 获取该元素data-src中存放的路径
          image.setAttribute("src", data_url); // 赋值给真实路径
          Observer.unobserve(image); // 停止观察
      }
  })
}
const Observer = new IntersectionObserver(callback); // 生成实例
IMGS.forEach(img => Observer.observe(img)) // 通过遍历对所有Img元素都进行观察

看下在浏览器中的具体效果吧(这里我开了3G慢网和禁止缓存来进行测试)


 总结:通过IntersectionObserver构造函数实现图片懒加载相较于滚动监听好的太多了,首先浏览器已经为我们提供了能够停止观察的api。同时,因为是观察行为,所以只要图片出现在了浏览器可视窗口中就会被触发api,我们就不需要再去考虑滚动的问题了,十分方便。当然,学会了IntersectionObserver,我们还可以去进行其他需要优化性能的操作。

所以,学到就是赚到,快去试试吧!

你可能感兴趣的:(逻辑处理,js进阶,前端,javascript)