Vue에서 이미지 지연 로딩 지침을 사용자 정의하는 방법은 무엇입니까? 다음 기사에서는 Vue2의 사용자 정의 이미지 지연 로딩 명령 "v-lazy"에 대해 심층적으로 소개합니다. 도움이 되기를 바랍니다.
개인 블로그의 프런트 엔드 페이지를 개발할 때 웹사이트의 응답 속도를 최적화하고 싶어서 이미지의 지연 로딩 효과를 구현하고 싶었습니다.
사용자 정의 명령 v-lazy
를 통해 구현했는데, 이 명령의 개발 과정과 그 어려움에 대한 해결 방법을 여러분과 공유하고 싶습니다. [관련 권장사항: vuejs 비디오 튜토리얼自定义指令v-lazy
实现的,所以在这跟大家分享一下这个指令的开发流程及其难点的解决方法。【相关推荐:vuejs视频教程】
自定义图片懒加载指令主要涉及以下三块知识:
下面我会对这些知识点进行一一介绍。
下面我只对自定义指令做简单的介绍,详细介绍大家可以参照Vue 官网 - 自定义指令。
钩子函数的参数主要有这四个el、binding、vnode、oldVnode
。
对事件总线不熟悉的朋友,可以参照该博客什么是 Vue 事件总线(EventBus)。
我们可以借助 vue 示例来实现事件总线,也可以自行封装;我使用了第一种方法。
因此事件总线配置文件---eventBus.js
的代码如下:
import Vue from "vue"; const eventBus = new Vue({}); /* * 事件名:mainScroll * 含义:主区域滚动条位置变化后触发 * 参数: * - 滚动的dom元素,如果是undefined,则表示dom元素已经不存在 */ //在Vue.prototype原型上注册事件总线,方便vue实例对象监听和触发 Vue.prototype.$bus = eventBus; //导出事件总线,方便在其他js模块监听和触发事件总线上的事件 export default eventBus;
首先Element.clientHeight
]1. 관련된 주요 지식에 대한 설명
el, 바인딩, vnode, oldVnode
네 가지가 포함됩니다. 🎜eventBus.js
의 코드는 다음과 같습니다. 🎜import Vue from "vue"; import App from "./App.vue"; import "./eventBus"; //引入事件总线 import vLazy from "./directives/lazy"; Vue.directive("lazy", vLazy); //全局注册指令 new Vue({ render: (h) => h(App), }).$mount("#app");
Element.clientHeight
는 🎜읽기 전용 속성🎜입니다. 다음 특성: 🎜content
与padding
,不包含border
、margin
与水平滚动条(如果存在)。另外改 API 会将获取的值四舍五入取整数。如果你需要小数结果,可以使用 element.getBoundingClientRect()方法。
示例图如下:
该 API 的详细文档可参照MDN - Element.clientHeight。
Element.getBoundingClientRect()
方法返回一个DOMRect
对象,其提供了元素的大小及其相对于视口的位置。
该方法无参数,返回值为DOMRect
对象,该对象的属性以下几个:
示意图如下:
该 API 的详细文档可以参照MDN - Element.getBoundingClientRect()
最终效果如下图:
由于在个人博客系统中图片懒加载指令使用的比较频繁,使用我选择了全局注册该指令。
另外因为我使用事件总线这方法来自己通信,使用还需引入事件总线配置文件---eventBus.js
所以 main.js入口文件
的代码如下:
import Vue from "vue"; import App from "./App.vue"; import "./eventBus"; //引入事件总线 import vLazy from "./directives/lazy"; Vue.directive("lazy", vLazy); //全局注册指令 new Vue({ render: (h) => h(App), }).$mount("#app");
使用 v-lazy 指令的示例代码如下:
<template> <div> <ul> <li> <img alt="Vue2에서 이미지 지연 로딩 명령을 사용자 정의하는 방법을 단계별로 안내합니다." > </li> </ul> </div> </template> <script> export default { data() { return { imgs: [ { id: "", src: "", alt: "", title: "", }, ], }; }, //下面的代码可以用组件混入来进行封装,从而优化代码结构 methods: { //触发mainScroll事件 handleMainScroll() { this.$bus.$emit("mainScroll", this.$refs.container); }, }, mounted() { //监听滚轮事件 this.$refs.container.addEventListener("scroll", this.handleMainScroll); }, beforeDestroy() { this.$bus.$emit("mainScroll");//参数传入undefined,表示dom元素已经不存在 //取消监听滚轮事件 this.$refs.container.removeEventListener("scroll", this.handleMainScroll); }, }; </script>
要实现图片懒加载效果,我们首先要思考以下四个关键问题:
如何监听容器的滚动条的滚动?
使用自定义指令哪些钩子函数?
如何判断图片 img 元素是否在用户的可见范围内?
如何处理图片 img 元素的加载?
对于这问题,由于我的博客系统在处理其他组件之间的传值问题时,使用了事件总线方法,所以为了方便,我也使用这一方法,当然大家可以针对实际场景使用其他方法来解决这问题。
所以我们要在 v-lazy 图片懒加载指令配置文件---lazy.js
文件中监听事件总线 eventBus 中的mainScroll事件
,同时为了性能优化,我们需要进行 mainScroll 事件的事件防抖
。
其中事件防抖工具函数---debounce.js
代码如下:
/** * @param {Function} fn 需要进行防抖操作的事件函数 * @param {Number} duration 间隔时间 * @returns {Function} 已进行防抖的函数 */ export default function (fn, duration = 100) { let timer = null; return (...args) => { clearTimeout(timer); timer = setTimeout(() => { fn(...args); }, duration); }; }
图片懒加载指令配置文件---lazy.js
该部分代码如下:
import eventBus from "@/eventBus"; //引入事件总线 import { debounce } from "@/utils"; //引入函数防抖工具函数 // 调用setImages函数,就可以处理那些符合条件的图片 function setImages() {} //监听事件总线中的mainScroll事件,该事件触发时调用setImages函数来加载图片 eventBus.$on("mainScroll", debounce(setImages, 50));
经过场景分析,我选用了inserted
和unbind
这两个钩子函数,当 img 元素刚插入父节点时收集 img 的信息,并在内部使用一个 imgs 数组存储已收集到的信息,当指令与元素解绑时,进行 imgs 数组清空操作。
另外我们还需获取图片 img 元素的 DOM 节点和 src 属性值
el参数
得到其 DOM 节点bindings.value参数
得到其 src 属性值所以此时图片懒加载指令配置文件---lazy.js
该部分代码如下:
import eventBus from "@/eventBus"; //引入事件总线 import { debounce } from "@/utils"; //引入函数防抖工具函数 // 调用setImages函数,就可以处理那些符合条件的图片 function setImages() {} //监听事件总线中的mainScroll事件,该事件触发时调用setImages函数来加载图片 eventBus.$on("mainScroll", debounce(setImages, 50)); //上面代码是3.1 如何监听容器的滚动条的滚动? //下面代码是3.2 使用自定义指令哪些钩子函数? let imgs = []; //存储收集到的的图片信息 当图片加载好后删除该图片信息 //调用setImage函数,就可以进行单张图片的加载 function setImage(img) {} export default { inserted(el, bindings) { //刚插入父节点时 收集img节点信息 const img = { dom: el, //img 元素DOM节点 src: bindings.value, //img的src属性值 }; imgs.push(img); //先将图片信息存储到imgs数组 setImage(img); // 立即判断该图片是否要加载 }, unbind(el) { //解绑时 删除 imgs 中的所有图片信息 imgs = imgs.filter((img) => img.dom !== el); }, };
对于上面这问题,我们先进行问题拆分:
1、获得用户的可见范围(视口)
Element.clientHeight
这 API。(如果还需要考虑宽度就再使用Element.clientWidth)2、获得图片 img 元素的位置信息
Element.getBoundingClientRect()
这 API。3、判断图片 img 元素是否在视口内
图片懒加载指令配置文件---lazy.js
该部分代码如下:
import eventBus from "@/eventBus"; //引入事件总线 import { debounce } from "@/utils"; //引入函数防抖工具函数 let imgs = []; //存储收集到的的图片信息 // 调用setImages函数,就可以处理那些符合条件的图片 function setImages() { for (const img of imgs) { setImage(img); // 处理该图片 } } //监听事件总线中的mainScroll事件,该事件触发时调用setImages函数来加载符合条件图片 eventBus.$on("mainScroll", debounce(setImages, 50)); //当图片加载好后删除该图片信息 export default { inserted(el, bindings) { //刚插入父节点时 收集img节点信息 const img = { dom: el, //img 元素DOM节点 src: bindings.value, //img的src属性值 }; imgs.push(img); //先将图片信息存储到imgs数组 setImage(img); // 立即判断该图片是否要加载 }, unbind(el) { //解绑时 删除 imgs 中的所有图片信息 imgs = imgs.filter((img) => img.dom !== el); }, }; //上面代码是3.1 如何监听容器的滚动条的滚动?+ 3.2 使用自定义指令哪些钩子函数? //下面代码是3.3 如何判断图片 img 元素是否在用户的可见范围内? //调用setImage函数,就可以进行单张图片的加载 function setImage(img) { const clientHeight = document.documentElement.clientHeight; //视口高度 const rect = img.dom.getBoundingClientRect(); //图片的位置信息 //取默认值150 是为了解决图片未加载成功时高度缺失的问题 const height = rect.height || 150; //图片的高度 // 判断该图片是否在视口范围内 if (rect.top >= -height && rect.top <h3 data-id="heading-16"><strong>3.4 如何处理图片 img 元素的加载?</strong></h3><p>由效果图我们可看出一开始所有 img 元素都是一张默认的 GIF 图片---<code>defaultGif</code>,等该 img 元素进入到视口范围时,开始加载该图片,加载完成后再进行替换。</p><p>这里我还进行一个优化操作,就是先新建一个 <code>Image 对象实例</code>,代替 img 元素加载图片,因为图片加载完成后会触发<code>onload事件</code>,所以我们只需对<code>onload事件</code>进行改写,在其内部执行 img 元素的 src 属性替换操作,这样就解决了加载过程中图片空白的情况。</p><p>所以图片懒加载指令配置文件---<code>lazy.js</code>完整的代码如下:</p><pre class="brush:php;toolbar:false">import eventBus from "@/eventBus"; //引入事件总线 import { debounce } from "@/utils"; //引入函数防抖工具函数 import defaultGif from "@/assets/default.gif"; //在assets静态文件夹下放入默认图 let imgs = []; //存储收集到的且未加载的图片信息 //调用setImage函数,就可以进行单张图片的加载 function setImage(img) { img.dom.src = defaultGif; // 先暂时使用默认图片 const clientHeight = document.documentElement.clientHeight; //视口高度 const rect = img.dom.getBoundingClientRect(); //图片的位置信息 //取默认值150 是为了解决图片未加载成功时 高度缺失的问题 const height = rect.height || 150; //图片的高度 // 判断该图片是否在视口范围内 if (-rect.top i !== img); //将已加载好的图片进行删除 } } // 调用setImages函数,就可以处理那些符合条件的图片 function setImages() { for (const img of imgs) { setImage(img); // 处理该图片 } } //监听事件总线中的mainScroll事件,该事件触发时调用setImages函数来加载符合条件图片 eventBus.$on("mainScroll", debounce(setImages, 50)); //当图片加载好后删除该图片信息 export default { inserted(el, bindings) { //刚插入父节点时 收集img节点信息 const img = { dom: el, //img 元素DOM节点 src: bindings.value, //img的src属性值 }; imgs.push(img); //先将图片信息存储到imgs数组 setImage(img); // 立即判断该图片是否要加载 }, unbind(el) { //解绑时 清空 imgs imgs = imgs.filter((img) => img.dom !== el); }, };
위 내용은 Vue2에서 이미지 지연 로딩 명령을 사용자 정의하는 방법을 단계별로 안내합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!