vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue-Lazyload 使用

Vue图片懒加载之Vue-Lazyload的使用

作者:muzidigbig

懒加载就是延时加载,即当需要用到的时候再去加载,本文主要介绍了Vue图片懒加载之Vue-Lazyload的使用,具有一定的参考价值,感兴趣的可以了解一下

一、什么叫懒加载

通俗讲 : 懒加载就是延时加载,即当需要用到的时候再去加载。
那什么叫做需要用到的时候?比如一个图片在没有出现在可视区域内,就已经加载当页面里了, 但只有滚动页面下方式才能看见, 则可以认为这个图片加载的"过早"了。

二、懒加载的优点

三、为什么使用懒加载

可以想象一个网页打开有成百上千的图片需要加载,页面会变得非常的卡顿,此时如果只是可视区域的图片加载,其他的图片可以暂时有一个占位 loading 图,等滚动它们到可视区域时再去请求真实图片并且替换就好了。vue-lazyload 插件就是解决此类问题的,对vue插件的写法不熟悉的可以先看一下vue插件

懒加载原理是什么

页面中的img元素,如果没有src属性,浏览器就不会发出请求去下载图片,只有通过javascript设置了图片路径,浏览器才会发送请求。

懒加载的原理就是先在页面中把所有的图片统一使用一张占位图进行占位,把真正的路径存在元素的“data-url”(这个名字起个自己认识好记的就行)属性里,当js监听到该图片元素进入可视窗口时,即将自定义属性中的地址存储到src属性中,达到懒加载的效果。

四、vue中如何实现懒加载

第一步: 安装

npm install vue-lazyload --save

第二步: 全局注册(main.js)

// main.js 文件
import VueLazyload from 'vue-lazyload'
// Vue.use(VueLazyload) //无配置项
// 配置项
const loadimage = require('assets/img/common/loading.gif')
// const errorimage = require('assets/img/common/error.gif')
Vue.use(VueLazyload, {
  preLoad: 1.3, //预加载的宽高比
  loading: loadimage, //图片加载状态下显示的图片
  // error: errorimage, //图片加载失败时显示的图片
  attempt: 1, // 加载错误后最大尝试次数
})
// img元素上使用v-lazy="src";<img v-lazy="showImage"/>

配置项的参数说明

描述默认选项
preLoad表示lazyload的元素,
距离页面底部距离的百分比.
计算值为(preload - 1)
1.3Number
error加载失败后图片地址'data-src'String
loading加载时图片地址'data-src'String
attempt图片加载失败后的重试次数3Number
listenEvents触发懒加载的事件['scroll',
'wheel',
'mousewheel',
'resize',
'animationend',
'transitionend',
'touchmove']
adapter注册img 的loading,loaded,error
三个状态的回调函数,
参数会暴露懒加载的img元素,
可以对其进行操作.
{ }
filterimg未加载之前,
解析到src 的时候注册的回调函数.
可以在加载图片之前,对src进行修改.
注册在filter下的所有的函数都会执行
{ }
lazyComponent是否启用懒加载组件.
<lazy-component>组件中的内容
只有在出现在preload的
位置中才会加载组件.
这个lazyloadComponent
组件有个缺点
就是,组件在加载前
是什么都不渲染的,
这样子的话,有可能会影响布局,
以及加载前到加载后的切换不好,
有点突兀和生硬.
false
dispatchEvent触发dom事件falseBoolean
throttleWait等待时长200Number
observer是否启用IntersectionObserver,
这个api有兼容问题
falseBoolean
observerOptionsIntersectionObserver选项{ rootMargin: '0px',
threshold: 0.1 }
silent不打印调试信息trueBoolean

因为src中的文件会被webpack编译,assets文件夹中的图片地址,会在编译过程中重命名。vue-lazyload是在main.js文件中引入,不会被webpack进行编译,因此vue-lazyload无法获得正确的图片地址,所以直接写相对地址就无法获取到图片正确地址

第三步: 写loading图片的样式(不是必须, 视情况而定)

img[lazy="loading"]{
  display:block;
  width:50px !important;
  height:50px !important;
  margin:0 auto;
}

第四步: 使用 ( :src--->v-lazy )

  <div class="lazyLoad">
    <ul>
      <li v-for="img in arr">
        <img v-lazy="img.thumbnail_pic_s">
      </li>
    </ul>
  </div>

这里有个坑需要注意如设置了翻页功能,且每一页都是请求的数据进行渲染。
会发现其他的数据都变了,唯独图片还是原来的图片。
由于使用的数据是父组件传过来的,第一个想到父组件axios异步请求的数据导致子组件可能数据没有动态更新。但监听了下数据,发现确实是改变了 .
解决办法只要加个key就行, 如下代码

<ul>  
    <li v-for="img in list">
        <img v-lazy="img.src" :key="img.src" >
    </li>
</ul>

五、js---懒加载的实现步骤?

1)首先,不要将图片地址放到src属性中,而是放到其它属性(data-original)中。

2)页面加载完成后,根据scrollTop判断图片是否在用户的视野内,如果在,则将data-original属性中的值取出存放到src属性中。

3)在滚动事件中重复判断图片是否进入视野,如果进入,则将data-original属性中的值取出存放到src属性中。

懒加载代码实现

方式一:原生js

元素距顶部的高度 - 页面被卷去的高度 <= 浏览器可视区的高度) 

来判断是否符合我们想要的条件.需要实时监听页面滚动时 图片的高度变化

<!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>Document</title>
    <style>
      * {
        padding: 0;
        margin: 0;
        list-style: none;
      }
      img {
        width: 400px;
        height: 300px;
      }
    </style>
    <script>
      window.onload = function () {
        var imgs = document.querySelectorAll("img");
        // 初始化执行
        lazyLoad(imgs);
        // 滚动执行
        window.addEventListener("scroll", function () {
          lazyLoad(imgs);
        });
 
        function lazyLoad(imgs) {
          for (let i = 0; i < imgs.length; i++) {
            var imgoffsetT = imgs[i].offsetTop; // 图片的距顶部的高度
            var wheight = window.innerHeight; // 浏览器可视区的高度
            var scrollT = document.documentElement.scrollTop; // 页面被卷去的高度
            if (imgoffsetT - scrollT <= wheight) {
              // 判断图片是否将要出现
              imgs[i].src = imgs[i].dataset.src; // 出现后将自定义地址转为真实地址
            }
          }
        }
      };
 
      /* 
        obj.getAttribute("属性名")
        通过元素节点的属性名称获取属性的值。
        使用data-前缀设置我们需要的自定义属性,来进行一些数据的存放,
        dataset 获取自定义属性值的使用
      */
    </script>
  </head>
  <body>
    <ul>
      <li>
        <img data-src="./img/img1.gif" src="./img/loading.gif" alt="" />
      </li>
      <li>
        <img data-src="./img/img2.gif" src="./img/loading.gif" alt="" />
      </li>
      <li>
        <img data-src="./img/img3.gif" src="./img/loading.gif" alt="" />
      </li>
      <li>
        <img data-src="./img/img4.gif" src="./img/loading.gif" alt="" />
      </li>
      <li>
        <img data-src="./img/img5.png" src="./img/loading.gif" alt="" />
      </li>
    </ul>
  </body>
</html>

方式二:    getBoundingClientRect()

<!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>Document</title>
    <style>
      * {
        padding: 0;
        margin: 0;
        list-style: none;
      }
      img {
        width: 400px;
        height: 300px;
      }
    </style>
    <script>
      window.onload = function () {
        var imgs = document.querySelectorAll("img");
        // 初始调动一次
        lazyLoad();
        window.addEventListener("scroll", throttle(lazyLoad, 1000), false);
 
 
        //函数1:封装判定图片是否在可视区
        function isInVisibleArea(imgOne) {
          const info = imgOne.getBoundingClientRect();
          //  获取页面可视区的高度,宽度
          let windowH = window.innerHeight;
          let windowW = window.innerWidth;
          // 限定参数在可视区内
          let res = info.bottom > 0 && info.top < windowH && info.right > 0 && info.left < windowW;
          return res;
        }
 
 
        //函数2: 封装滚动时重新加载函数
        function lazyLoad() {
          for (let i = 0; i < imgs.length; i++) {
            const imgOne = imgs[i];
            // 判定是否在可视区内
            if (isInVisibleArea(imgOne)) {
              // 替换src方法一:
              // imgOne.src = imgOne.getAttribute("data-src");
              // 替换src方法二:
              imgOne.src = imgOne.dataset.src;
              // imgs.splice(i,1)
              // i--;
            }
            console.log("我滚了"); //所以要做节流操作
          }
        }
 
 
        //函数3:节流函数
        /* 
        参数1:函数
        参数2:执行时间
         */
        function throttle(fn, time = 250) {
          let lastTime = null;
          return function (...args) {
            const now = Date.now(); //当前时间
            if (now - lastTime >= time) {
              fn();//帮助执行函数,改变上下文
              lastTime = now;
            }
          };
        }
 
      };
   
      /* 
      getBoundingClientRect()
           ——获取元素位置,这个方法没有参数
           ——用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。
           ——是DOM元素到浏览器可视范围的距离(不包含文档卷起的部分)。
      该函数返回一个Object对象,该对象有6个属性:top,lef,right,bottom,width,height;
 */
 
    </script>
  </head>
  <body>
    <ul>
      <li>
        <img data-src="./img/img1.gif" src="./img/loading.gif" alt="" />
      </li>
      <li>
        <img data-src="./img/img2.gif" src="./img/loading.gif" alt="" />
      </li>
      <li>
        <img data-src="./img/img3.gif" src="./img/loading.gif" alt="" />
      </li>
      <li>
        <img data-src="./img/img4.gif" src="./img/loading.gif" alt="" />
      </li>
      <li>
        <img data-src="./img/img5.png" src="./img/loading.gif" alt="" />
      </li>
    </ul>
  </body>
</html>

上面的方法需要频繁触发 scroll 事件,很容易造成卡顿或者页面性能问题。 

方式三:IntersectionObserver(callback)

1.概念 

IntersectionObserve 是浏览器提供的一个原生构造函数,它也被称作交叉观察器。 它可以观察我们的元素是否可见,也就是是否和可视区发生交叉。官网的解释:IntersectionObserver 接口提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。祖先元素与视窗(viewport)被称为根(root)。

官网说的稍微晦涩一点,我们通俗的给大家解释一下,结合一张图应该就很好里面了。
通俗的解释:我们可以使用 IntersectionObserver 接口观察一个元素,观察它是否进入了可视区,这个可视区可以相对于视窗或者祖先元素。

上面的图就很形象的描述了一个元素逐步出现在可视区内的过程,当元素和可视区发生交叉时,则代表进入可视区内了。而我们的 “交叉观察器” IntersectionObserve 就和名字一样,专门用来观察何时交叉。 

2.基本使用

IntersectionObserve 使用起来很简单,我们了解了它接收的参数以及携带的方法如何使用后,便可以很快的上手。

2.1 初始化实例

因为它是一个构造函数,所以我们可以使用 new 的方式实例化它,代码如下:

<script>
  let IO = new IntersectionObserver(callback, options);
</script>

 该构造函数接收两个参数:

2.2 回调函数参数callback 会接收两个参数

主要解释如下:

entries:它是一个 IntersectionObserverEntry 对象数组 ,IntersectionObserverEntry 主要存储的是一些观察元素的信息,主要有以下 7 个属性:

observer它返回的是被调用的 IntersectionObserve 实例,我们通常无需操作。

2.3 options 配置options 是构造函数的第二个参数,是一个对象的形式,它主要一些配置信息,主要配置项有如下几个:

看图理解:

let viewport = document.getElementById("viewport"); // 可视区域
let options = {
  root: viewport,
  threshold: [0, 0.5, 1],
  rootMargin: '30px 100px 20px'
}

2.4 实例方法

初始化实例后,我们就可以调用实例方法了。IntersectionObserver 实例常用的方法常主要有下面几个:

可以先简单演示一下,看看何时触发 callback。

3.代码演示

3.1 查看 entries 和 observe

我们先来看一下回调函数里面默认传递的参数打印出来是什么:entries 和 observe。
示例代码:

<head>
  <style>
    .viewport {
      width: 300px;
      height: 200px;
      border: 1px solid blue;
      overflow: auto;
    }
    .box1 {
      height: 600px;
      width: 100%;
    }
    .observed {
      width: 100px;
      height: 100px;
      border: 1px solid green;
    }
  </style>
</head>


<body>
  <div class="viewport" id="viewport">
    <div class="box1">
      <div class="observed" id="observed"></div>
    </div>
  </div>
</body>
<script>
  let viewport = document.getElementById("viewport"); // 可视区域
  let observed = document.getElementById("observed"); // 被观察元素
  let options = {
    root: viewport, // 指定可视区元素
  }
  let IO = new IntersectionObserver(IOCallback, options); // 初始化实例
  IO.observe(observed); // 开始观察


  // 回调函数
  function IOCallback(entries, observer) {
    console.info("entries", entries);
    console.info("observer", observer);
  }
</script>

输出结果:

这里的代码还比较简单,我们这里设置了视图窗口为我们指定的 id 为 viewport 的元素,被观察元素为 id 为 observed 的元素。当我们刷新页面的时候,IOCallback 回调函数便会执行,且打印了 entries 和 observe,至于它们中每个参数代表的意义大家可以参照上一节。 

3.2 实现图片懒加载

图片懒加载是我们非常常见的一个场景了,这里我们拿这个场景距离相信大家可以更加容易理解。
需求背景:我们有非常多的图片,如果一次性全部渲染,非常消耗性能。所以我们需要实现图片出现在可视区域内后在进行渲染加载。
实现思路:

<!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>Document</title>
    <style>
      * {
        padding: 0;
        margin: 0;
        list-style: none;
      }
      img {
        width: 400px;
        height: 300px;
      }
    </style>
  </head>
  <body>
    <ul id="view">
      <li>
        <img data-src="./img/img1.gif" src="./img/loading.gif" alt="" />
      </li>
      <li>
        <img data-src="./img/img2.gif" src="./img/loading.gif" alt="" />
      </li>
      <li>
        <img data-src="./img/img3.gif" src="./img/loading.gif" alt="" />
      </li>
      <li>
        <img data-src="./img/img4.gif" src="./img/loading.gif" alt="" />
      </li>
      <li>
        <img data-src="./img/img5.png" src="./img/loading.gif" alt="" />
      </li>
    </ul>
 
    <script>
      const imgs = document.querySelectorAll("img");
      const callback = (res) => {
        //res 是观察的元素数组   info 每个被观察的图片信息
        // 循环所有观察元素
        res.forEach((info) => {
          //  isIntersecting 目标是否被观察到,返回布尔值
          if (info.isIntersecting) {
            // img 就是当前的图片标签
            const img = info.target;
            img.src = img.getAttribute("data-src");
            // 真实地址替换后 取消对它的观察
            obs.unobserve(img);
            console.log("触发");
          }
        });
      };
      const obs = new IntersectionObserver(callback);// 实例化 IntersectionObserver
      // 遍历imgs所有的图片,然后给每个图片添加观察实例
      imgs.forEach((img) => {
        //  observe : 被调用的IntersectionObserver实例。给每个图片添加观察实例
        obs.observe(img);
      });
 
   /* IntersectionObserver(callback) 
        callback回调触发两次,看见了出发,看不见也触发
   */
    </script>
  </body>
</html>

警告:IE 不兼容

到此这篇关于Vue 图片懒加载 之 Vue-Lazyload的使用的文章就介绍到这了,更多相关Vue-Lazyload 使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文