2021年11月24日

懒加载(js/js Api/自定义vue指令)

作者 rourou

图片实现懒加载,实现方式是判断是否出现在可见视图中。

第一种:图片距离文档顶部的高度,与视口高度及滚动高度相比较判断是否出现在可见视图中。(查看实例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>图片懒加载/延迟加载</title>
  <style>
    img{
      width: 100%;
      min-height: 300px;
    }
  </style>
</head>
<body>
  <img class="img" data-src="imgs/1.jpg" alt="">
  <img class="img" data-src="imgs/2.jpg" alt="">
  <img class="img" data-src="imgs/3.jpg" alt="">
  <img class="img" data-src="imgs/4.jpg" alt="">
 
<script>
  const imgs = document.getElementsByClassName('img');
  let n = 0;
  lazyLoad();
  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 = n + 1;

      }
    }
     
  }
 
  window.addEventListener('scroll',lazyLoad);
</script>
</body>
</html>

第二种:通过js Api(IntersectionObserver)判断是否出现在可见视图中。

IntersectionObserver是浏览器原生提供的构造函数,接受两个参数:callback是可见性变化时的回调函数,option是配置对象(该参数可选)。构造函数的返回值是一个观察器实例。实例的observeunobservedisobserve方分别指开始观察哪个 DOM 节点、停止观察、关闭观察。

目标元素的可见性变化时,会触发callback;一般会触发两次,次是目标元素刚刚进入视口,另一次是完全离开视口。callback函数的参数(entries)是一个数组,每个成员都是一个IntersectionObserverEntry对象。可以通过对象中intersectionRatio(目标元素的可见比例)值判断,完全可见时为1,完全不可见时小于等于0

查看实例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>图片懒加载/延迟加载</title>
  <style>
    img{
      width: 100%;
      min-height: 300px;
    }
  </style>
</head>
<body>
    <img class="img" data-src="imgs/1.jpg" alt="">
    <img class="img" data-src="imgs/2.jpg" alt="">
    <img class="img" data-src="imgs/3.jpg" alt="">
    <img class="img" data-src="imgs/4.jpg" alt="">
   
  <script>
    const imgs = document.getElementsByClassName('img');
 
  if(IntersectionObserver){
    let lazyLoadObser = new IntersectionObserver((entries,observer) => {
      entries.forEach((entry,index) => {
        let lazyImage = entry.target;
        if(entry.intersectionRatio > 0){
          lazyImage.src = lazyImage.getAttribute('data-src');
          lazyLoadObser.unobserve(lazyImage);
        }
 
      })
    })
 
    for(let i = 0; i<imgs.length; i++){
      lazyLoadObser.observe(imgs[i]);
    }
 
  }
 
</script>
</body>
</html>

通过js API(IntersectionObserver)封装自定义vue指令(查看实例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>vue自定义指令 图片懒加载/延迟加载</title>
  <style>
    img{
      width: 100%;
      min-height: 300px;
    }
  </style>
</head>
<body>
  <div id="app">
    <p v-for="item in imgs">
      <img v-lazyload="item">
    </p>
  </div>
<script src="../demopage/js/vue.min.js"></script>
<script>
  Vue.directive('lazyload',{
    bind:function(el,bind){
    let lazyLoadObser = new IntersectionObserver((entries,observer) => {
      entries.forEach((entry,index) => {
        let lazyImage = entry.target;
        if(entry.intersectionRatio > 0){
          lazyImage.src = bind.value;
          lazyLoadObser.unobserve(lazyImage);
        }
 
      })
    })
      lazyLoadObser.observe(el);
    }
  })
  var app = new Vue({
    el:"#app",
    data:{
      imgs:[
        'imgs/1.jpg',
        'imgs/2.jpg',
        'imgs/3.jpg',
        'imgs/4.jpg',
      ]
    }
  })
</script>
</body>
</html>