实现一个Vue自定义指令懒加载的方法示例


Posted in Javascript onJune 04, 2020

在项目中如果有大量的图片需要加载的时候,就可以考虑使用懒加载了,懒加载其实就是监听浏览器的滚动,当滚动到一定的范围的时候就将图片的真实路径赋给src,然后取消监听。实现的方法也比较简单,可以通过懒加载的插件实现,也可以手写,手写通过vue自定义指令来实现,一般情况自定义指令用的也不多,比较vue自带的就够用了,大型复杂的项目的可能用的多。

什么是图片懒加载

当我们向下滚动的时候图片资源才被请求到,这也就是我们本次要实现的效果,进入页面的时候,只请求可视区域的图片资源这也就是懒加载。

比如我们加载一个页面,这个页面很长很长,长到我们的浏览器可视区域装不下,那么懒加载就是优先加载可视区域的内容,其他部分等进入了可视区域在加载。

这个功能非常常见,你打开淘宝的首页,向下滚动,就会看到会有图片不断的加载;你在百度中搜索图片,结果肯定成千上万条,不可能所有的都一下子加载出来的,很重要的原因就是会有性能问题。你可以在Network中查看,在页面滚动的时候,会看到图片一张张加载出来。

实现一个Vue自定义指令懒加载的方法示例

为什么要做图片懒加载

懒加载是一种网页性能优化的方式,它能极大的提升用户体验。就比如说图片,图片一直是影响网页性能的主要元凶,现在一张图片超过几兆已经是很经常的事了。如果每次进入页面就请求所有的图片资源,那么可能等图片加载出来用户也早就走了。所以,我们需要懒加载,进入页面的时候,只请求可视区域的图片资源。

总结出来就两个点:

1.全部加载的话会影响用户体验

2.浪费用户的流量,有些用户并不像全部看完,全部加载会耗费大量流量。

懒加载原理

图片的标签是 img标签,图片的来源主要是 src属性,浏览器是否发起加载图片的请求是根据是否有src属性决定的。

所以可以从 img标签的 src属性入手,在没进到可视区域的时候,就先不给 img 标签的 src属性赋值。

懒加载实现

实现效果图:

实现一个Vue自定义指令懒加载的方法示例

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Document</title>
 <style>
  div {
   display: flex;
   flex-direction: column;
  }
  img {
   width: 100%;
   height: 300px;
  }
 </style>
</head>
<body>
 <div>
  <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657907683.jpeg">
  <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657913523.jpeg">
  <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657925550.jpeg">
  <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657930289.jpeg">
  <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657934750.jpeg">
  <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657918315.jpeg">
 </div>
</body>
</html>

监听滚动根据offsetTop判断

const imgs = [...document.getElementsByTagName('img')];
 let n = 0;

 lazyload();
 function throttle(fn, wait) {
 let timer = null;
 return function(...args) {
  if(!timer) {
   timer = setTimeout(() => {
    timer = null;
    fn.apply(this, args)
   }, wait)
  }
 }
 }
 window.addEventListener('scroll', throttle(lazyload, 200));
 
 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 = i + 1;
  }
  
 }
 }

可能会存在下面几个问题:

  • 每次滑动都要执行一次循环,如果有1000多个图片,性能会很差
  • 每次读取 scrollTop 都会引起回流
  • scrollTop跟DOM的嵌套关系有关,应该根据getboundingclientrect获取
  • 滑到最后的时候刷新,会看到所有的图片都加载了

IntersectionObserver

const imgs = [...document.getElementsByTagName('img')];
// 当监听的元素进入可视范围内的会触发回调
 if(IntersectionObserver) {
  let lazyImageObserver = new IntersectionObserver((entries, observer) => {
   entries.forEach((entry, index) => {
    let lazyImage = entry.target;
    // 相交率,默认是相对于浏览器视窗
    if(entry.intersectionRatio > 0) {
    lazyImage.src = lazyImage.getAttribute('data-src');
    // 当前图片加载完之后需要去掉监听
     lazyImageObserver.unobserve(lazyImage);
    }

   })
  })
  for(let i = 0; i < imgs.length; i++) {
  lazyImageObserver.observe(imgs[i]);
  }
 }

codePen

vue自定义指令-懒加载

Vue自定义指令

下面的api来自官网自定义指令:

钩子函数

  • bind: 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  • inserted: 被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
  • update: 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
  • componentUpdated: 指令所在组件的 VNode 及其子 VNode 全部更新后调用。
  • unbind: 只调用一次,指令与元素解绑时调用。

钩子函数参数

指令钩子函数会被传入以下参数:

  • el:指令所绑定的元素,可以用来直接操作 DOM。
  • binding:一个对象,包含以下 property:
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
    • oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
  • vnode:Vue 编译生成的虚拟节点。
  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

实现 v-lazyload 指令

<!DOCTYPE html>
<html lang="en">
 <head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
  <style>
   img {
    width: 100%;
    height: 300px;
   }
  </style>
 </head>
 <body>
  <div id="app">
   <p v-for="item in imgs" :key="item">
    <img v-lazyload="item">
   </p>
  </div>
 </body>
 <script src="https://cdn.jsdelivr.net/npm/vue"></script>
 <script>
  Vue.directive("lazyload", {
   // 指令的定义
   bind: function(el, binding) {
    let lazyImageObserver = new IntersectionObserver((entries, observer) => {
     entries.forEach((entry, index) => {
      let lazyImage = entry.target;
      // 相交率,默认是相对于浏览器视窗
      if(entry.intersectionRatio > 0) {
       lazyImage.src = binding.value;
       // 当前图片加载完之后需要去掉监听
       lazyImageObserver.unobserve(lazyImage);
      }

     })
    })
    lazyImageObserver.observe(el);
   },
  });
  var app = new Vue({
   el: "#app",
   data: {
    imgs: [
     'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657907683.jpeg',
     'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657913523.jpeg',
     'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657925550.jpeg',
     'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657930289.jpeg',
     'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657934750.jpeg',
     'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657918315.jpeg',
    ]
   },
  });
 </script>
</html>

codePen

参考

延迟加载(Lazyload)三种实现方式

原生js实现图片懒加载(lazyLoad)

到此这篇关于实现一个Vue自定义指令懒加载的方法示例的文章就介绍到这了,更多相关Vue自定义指令懒加载内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
js 中的switch表达式使用示例
Jun 03 Javascript
JS修改iframe页面背景颜色的方法
Apr 01 Javascript
javascript制作照片墙及制作过程中出现的问题
Apr 04 Javascript
JavaScript给每一个li节点绑定点击事件的实现方法
Dec 01 Javascript
详解微信小程序 相对定位和绝对定位
May 11 Javascript
Angularjs上传图片实例详解
Aug 06 Javascript
vuejs使用FormData实现ajax上传图片文件
Aug 08 Javascript
vue动态路由实现多级嵌套面包屑的思路与方法
Aug 16 Javascript
js通过Date对象实现倒计时动画效果
Oct 27 Javascript
微信小程序实现左滑动删除效果
Mar 30 Javascript
layui输入框只允许输入中文且判断长度的例子
Sep 18 Javascript
js实现鼠标点击页面弹出自定义文字效果
Dec 24 Javascript
vue基础知识--axios合并请求和slot
Jun 04 #Javascript
vue webpack build资源相对路径的问题及解决方法
Jun 04 #Javascript
微信小程序学习总结(一)项目创建与目录结构分析
Jun 04 #Javascript
JavaScript冒泡算法原理与实现方法深入理解
Jun 04 #Javascript
js实现无刷新监听URL的变化示例代码详解
Jun 03 #Javascript
JQuery实现折叠式菜单的详细代码
Jun 03 #jQuery
JavaScript字符和ASCII实现互相转换
Jun 03 #Javascript
You might like
PHP在XP下IIS和Apache2服务器上的安装
2006/09/05 PHP
discuz Passport 通行证 整合笔记
2008/06/30 PHP
PHP实现批量生成App各种尺寸Logo
2015/03/19 PHP
thinkphp查询,3.X 5.0方法(亲试可行)
2017/06/17 PHP
js实现运行代码需要刷新的解决方法
2007/08/18 Javascript
jQuery教程 $()包装函数来实现数组元素分页效果
2013/08/13 Javascript
javascript打印html内容功能的方法示例
2013/11/28 Javascript
jquery live()调用不存在的解决方法
2014/02/26 Javascript
利用js实现禁止复制文本信息
2015/06/03 Javascript
ECMAScript6块级作用域及新变量声明(let)
2015/06/12 Javascript
谈一谈javascript闭包
2016/01/28 Javascript
javaScript数组迭代方法详解
2016/04/14 Javascript
url传递的参数值中包含&amp;时,url自动截断问题的解决方法
2016/08/02 Javascript
JavaScript数据操作_浅谈原始值和引用值的操作本质
2016/08/23 Javascript
关于javascript事件响应的基础语法总结(必看篇)
2016/12/26 Javascript
jQuery基于事件控制实现点击显示内容下拉效果
2017/03/07 Javascript
JS异步文件上传(兼容IE8+)
2017/04/02 Javascript
jQueryUI Sortable 应用Demo(分享)
2017/09/07 jQuery
layui select获取自定义属性方法
2018/08/15 Javascript
微信公众平台获取access_token的方法步骤
2019/03/29 Javascript
jQuery创建折叠式菜单
2019/06/15 jQuery
如何进行微信公众号开发的本地调试的方法
2019/06/16 Javascript
vue实现图片按比例缩放问题操作
2020/08/11 Javascript
[01:32]TI奖金增速竟因它再创新高!DOTA2勇士令状不朽珍藏Ⅰ饰品欣赏
2018/05/18 DOTA
[01:06]DOTA2小知识课堂 Ep.01 TP出门不要忘记帮队友灌瓶哦
2019/12/05 DOTA
linux系统使用python获取内存使用信息脚本分享
2014/01/15 Python
Python中的defaultdict模块和namedtuple模块的简单入门指南
2015/04/01 Python
Python中的map()函数和reduce()函数的用法
2015/04/27 Python
Python实现学校管理系统
2018/01/11 Python
python 实现的发送邮件模板【普通邮件、带附件、带图片邮件】
2019/07/06 Python
Django实现跨域请求过程详解
2019/07/25 Python
python GUI库图形界面开发之PyQt5切换按钮控件QPushButton详细使用方法与实例
2020/02/28 Python
基于Python实现简单学生管理系统
2020/07/24 Python
使用CSS3的appearance属性改变任何元素的浏览器默认风格
2012/12/24 HTML / CSS
电脑售后服务承诺书
2014/03/27 职场文书
windows11选中自动复制怎么开启? Win11自动复制所选内容的方法
2022/07/23 数码科技