现代化懒加载的方式

2018-02-06  本文已影响18人  流动码文

现代化懒加载的方式

为什么需要懒加载

通常用户打开网页时,整个网页的内容将被下载并且呈现在一个页面中,虽然允许浏览器缓存页面,但是不能保证用户查看所有下载的的内容,例如一个照片墙应用,可能用户仅仅查看第一个图片之后离开,结果就是白白浪费了内存和带宽。因此我们需要当用户需要访问页面的一部分时才去加载内容,而不是一看是就去加载全部内容。

如何实现懒加载

当有人向网页(图像,视频)等资源,资源引用一个小的占位符,当用户浏览网页,实际的资源被浏览器缓存,并且当资源在屏幕上可见时替换占位符,例如,如果用户加载网页并立即离开网页,则除了网页的顶部之外没有任何内容被加载。

<figure style="display: block; margin: 2.7rem auto; text-align: center;"> image

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 2.7rem; color: rgb(144, 144, 144);"></figcaption>

</figure>

懒加载具体实现

以加载图片为例子,我们需要将img标签中设置一个data-src属性,它指向的是实际上我们需要加载的图像,而imgsrc指向一张默认的图片,如果为空的话也会向服务器发送请求。

<img src="default.jpg" data-src="www.example.com/1.jpg">

之后当用户访问的可视区域的img元素时,将src得值替换为data-src指向的实际资源加载的图像

具体代码

const lazy = (el) => {
 let scrTop = getTop();
 let windowHeight = document.documentElement.clientHeight;
 function getTop(){
  return document.documentElement.scrollTop || document.body.scrollTop; 
 }
 function getOffset(node){
  return node.getBoundingClientRect().top + scrTop;
 }
 function inView(node){
  // 设立阈值
 const threshold = 0;
 const viewTop = scrTop;
 const viewBot = viewTop + windowHeight;

 const nodeTop = getOffset(node);
 const nodeBot = nodeTop + node.offsetHeight;

 const offset = (threshold / 100) * windowHeight;
 console.log((nodeBot >= viewTop - offset), (nodeTop <= viewBot + offset))
    return (nodeBot >= viewTop - offset) && (nodeTop <= viewBot + offset)
 }
 function check(node){
   let el = document.querySelector(node);
   let images = [...el.querySelectorAll('img')];
   images.forEach(img => {
    if(inView(img)){
     img.src = img.dataset.src;
    }
   })
 }
 check(el);
}

window.onscroll = function(){
 lazy('.foo');
}

现代化懒加载实现方法

通过上面例子的实现,我们要实现懒加载都需要去监听scroll事件,尽管我们可以通过函数节流的方式来阻止高频率的执行函数,但是我们还是需要去计算scrollTop,offsetHeight等属性,有没有简单的不需要计算这些属性的方式呢,答案是有的---IntersectionObserver

根据MDN:

IntersectionObserver API为开发者提供了一种可以异步监听目标元素与其祖先或视窗(viewport)处于交叉状态的方式。祖先元素与视窗(viewport)被称为根(root)。

简单来说就是观察一个元素和另一个元素是否重叠。

IntersectionObserver初始化的过程中提供了三个主要元素的配置:

image.png
<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 2.7rem; color: rgb(144, 144, 144);"></figcaption>

</figure>
image.png
<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 2.7rem; color: rgb(144, 144, 144);"></figcaption>

</figure>
image.png
<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 2.7rem; color: rgb(144, 144, 144);"></figcaption>

</figure>

为了告诉我们`intersectionObserver`我们想要得配置,我们只需要将我们得`config`对象和我们的回调函数一起传递到Observer构造函数中
const config = {
    root: null,
    rootMargin: '0px',
    threshold: 0.5
}
let observer = new IntersectionObserver(fucntion(entries){
    // ...
}, config)

现在我们需要去给IntersectionObserver实际观察的元素

const img = document.querySelector('image');
observer.observe(img);

关于这个实际观察的元素需要注意几点

const images = document.querySelecttorAll('img');
images.forEach(image => {
    observer.observe(image)
})

IntersectionObserver回调函数

new IntersectionObserver(function(entries, self))

entries我们得到我们的回调函数作为Array是特殊类型的:IntersectionObserverEntry首先IntersectionObserverEntry含有三个不同的矩形的信息

image.png
target则返回要观察的元素 好了

简单介绍完,让我们回到正题,用这个IntersectionObserver来实现代化的懒加载方式吧

const images = document.querySelectorAll('[data-src]')
const config = {
    rootMargin: '0px',
    threshold: 0
};
let observer = new IntersectionObserver((entries, self)=>{
    entries.forEach(entry => {
        if(entry.isIntersecting){
         // 加载图像
         preloadImage(entry.target);
         // 解除观察
           self.unobserve(entry.target)
        }
    })
}, config)

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

function preloadImage(img) {
  const src = img.dataset.src
  if (!src) { return; }
  img.src = src;
}

相比于之前懒加载的方式是不是更加简洁,而且只有当观察元素和捕捉框架交叉或重叠时,才会触发回掉函数(加载页面时也会触发回调函数,不过我们可以用isIntersecting来进行判断是否和观察元素相交)

延迟加载的好处

该方法目前有兼容性问题, github上有polyfill
https://github.com/w3c/IntersectionObserver/tree/master/polyfill

参考:

MDN

Now You See Me: How To Defer, Lazy-Load And Act With IntersectionObserver

What is Lazy Loading?

上一篇 下一篇

猜你喜欢

热点阅读