当前位置: 首页 > 编程笔记 >

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

孔理
2023-03-14
本文向大家介绍实现一个Vue自定义指令懒加载的方法示例,包括了实现一个Vue自定义指令懒加载的方法示例的使用技巧和注意事项,需要的朋友参考一下

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

什么是图片懒加载

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

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

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

为什么要做图片懒加载

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

总结出来就两个点:

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

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

懒加载原理

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

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

懒加载实现

实现效果图:

<!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自定义指令懒加载内容请搜索小牛知识库以前的文章或继续浏览下面的相关文章希望大家以后多多支持小牛知识库!

 类似资料:
  • 本文向大家介绍Vue 自定义指令实现一键 Copy功能,包括了Vue 自定义指令实现一键 Copy功能的使用技巧和注意事项,需要的朋友参考一下 先看下效果图: 指令是啥? 按照惯例,先请出官方的解释: 指令 (Directives) 是带有 v- 前缀的特殊特性。指令特性的值预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其

  • 本文向大家介绍vue实现路由懒加载及组件懒加载的方式,包括了vue实现路由懒加载及组件懒加载的方式的使用技巧和注意事项,需要的朋友参考一下 一、为什么要使用路由懒加载   为给客户更好的客户体验,首屏组件加载速度更快一些,解决白屏问题。 二、定义   懒加载简单来说就是延迟加载或按需加载,即在需要的时候的时候进行加载。 三、使用   常用的懒加载方式有两种:即使用vue异步组件 和 ES中的imp

  • 本文向大家介绍vue 使用自定义指令实现表单校验的方法,包括了vue 使用自定义指令实现表单校验的方法的使用技巧和注意事项,需要的朋友参考一下 笔者近期在公司的项目中使用自定义指令完成了表单校验。 这里将思路分享给大家,并写了一个小demo。这个自定义指令还需要大家自行完善。 demo可见Github:vue-form-param-check 首先关于自定义指令的介绍可以参考官网。 首先,在git

  • 本文向大家介绍PHP实现懒加载的方法,包括了PHP实现懒加载的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了PHP实现懒加载的方法。分享给大家供大家参考。具体分析如下: 寻常php的加载是通过include(),require()等方法来加载外部文件,之后再通过实例调用方法或直接调用静态方法,而这样子写引入语句实在很麻烦,有的框架会将特定路径的文件全部引入,直接实例化就能使用,但这样

  • 简介 除了默认设置的核心指令( v-model 和 v-show ),Vue 也允许注册自定义指令。注意,在 Vue2.0 里面,代码复用的主要形式和抽象是组件——然而,有的情况下,你仍然需要对纯 DOM 元素进行底层操作,这时候就会用到自定义指令。下面这个例子将聚焦一个 input 元素,像这样: Vue.directive('focus', { inserted: function (el)

  • 1. 前言 本小节我们介绍 Vue 中的自定义指令。包括全局指令的注册、局部指令的注册、指令钩子函数的使用以及动态指令传参。其中,指令钩子函数和动态指令参数是本节的难点。 同学们需要充分理解每个指令钩子函数执行的时机、对动态指令参数多加练习才能对指令的使用得心应手。 2. 慕课解释 Vue 除了提供了默认内置的指令外,还允许开发人员根据实际情况自定义指令,它的作用价值在于当开发人员在某些场景下需要