python可以做网站模板吗,免费图片尺寸在线修改,郑州快速建站模板,做网站可以用新建项目的方式吗Vue3实现图片懒加载及自定义懒加载指令 前言1.使用vue3-lazyload插件2.自定义v-lazy懒加载指令2.1 使用VueUse2.2 使用IntersectionObserver 前言
图片懒加载是一种常见性能优化的方式#xff0c;它只去加载可视区域图片#xff0c;而不是在网页加载完毕后就立即加载所有图片… Vue3实现图片懒加载及自定义懒加载指令 前言1.使用vue3-lazyload插件2.自定义v-lazy懒加载指令2.1 使用VueUse2.2 使用IntersectionObserver 前言
图片懒加载是一种常见性能优化的方式它只去加载可视区域图片而不是在网页加载完毕后就立即加载所有图片能减少很多不必要的请求极大的提升用户体验。
图片懒加载的实现原理在图片没进入可视区域的时候只需要让 img 标签的 src 属性指向一张默认图片在它进入可视区后再替换它的 src 指向真实图片地址即可。
本文就分享一下在vue3中实现图片懒加载的几种方式包括使用插件以及自定义指令实现的最终效果如下图所示
1.使用vue3-lazyload插件
第一种方式就是使用插件使用插件的方式非常简单只需要简单的几步即可实现。
Vue2中可以使用vue-lazyload插件来实现图片懒加载在Vue3中可以使用vue3-lazyload插件实现图片懒加载。
1.安装vue3-lazyload插件
$ npm i vue3-lazyload
# or
$ yarn add vue3-lazyload
# or
$ pnpm i vue3-lazyload2.main.js入口文件注册插件
import { createApp } from vue;
import App from ./App.vue;
//引入图片懒加载插件
import Lazyload from vue3-lazyload;const app createApp(App);//注册插件
app.use(Lazyload, {loading: /assets/images/default.png,//可以指定加载中的图像error: /assets/images/err.png,//可以指定加载失败的图像
});app.mount(#app);3.模板中使用v-lazy指令来延迟加载图像
templateul classcontainerli v-foritem in imgList :keyitem.idimg v-lazyitem.url classitem //li/ul
/templatescript langts setup
import { reactive } from vue;
const data [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((i) {return {id: ${i},url: /assets/images/${i}.jpg,};
});
const imgList reactive(data);
/scriptstyle scoped langscss
.container {width: 100vw;height: 100vh;overflow: auto;.item {width: 100%;height: 200px;}
}
/style2.自定义v-lazy懒加载指令
下面一种方式是自定义一个懒加载的指令如何实现呢
图片懒加载的核心是监听图片是否进入可视区域如果进入就替换src即懒加载指令的核心。
网上看了很多教程大多都使用Element.getBoundingClientRect()这个方法该方法返回一个 DOMRect 对象提供了元素的大小及其相对于视口的位置然后监听滚动条事件通过img.getBoundingClientRect()进行一系列的比较来判断图片是否在视口内这种方式略显复杂。其实只要我们能够简化判断图片是否进入可视区域这一流程实现一个自定义的懒加载指令就很简单了。
有没有什么简化的方式呢
可以通过VueUse中的useIntersectionObserver和原生的IntersectionObserver api来简化判断图片是否进入可视区域下面就分别通过这两种简化的方式来实现一个自定义的懒加载指令。
2.1 使用VueUse
VueUse 是什么?
一款基于Vue组合式API的函数工具集。以上是官方网站关于它的定义。
简单的说就是一个工具函数包它可以帮助你快速实现一些常见的功能。比如下面的一些
useLocalStorage提供在本地存储中保存和获取数据的功能。useMouse提供跟踪鼠标位置和鼠标按下状态的功能。useDebounce提供防抖功能。useThrottle提供节流功能。useIntersectionObserver提供对元素是否可见进行观察的功能可用于实现懒加载等效果。
本文要用到的就是其中的useIntersectionObserver这个函数来监听图片的可见性。
首先安装 VueUse
npm i vueuse/coremain.js入口文件导入
import { createApp } from vue;
import App from ./App.vue;//从vueuse/core中导入useIntersectionObserver函数
import { useIntersectionObserver } from vueuse/core;const app createApp(App);app.mount(#app);directive注册v-lazy全局指令
//main.js
//注册v-lazy全局指令使v-lazy在所有组件中都可用
app.directive(lazy, {//节点挂载完成后调用mounted(el, binding) {useIntersectionObserver(el, ([{ isIntersecting }]) {//判断当前监听元素是否进入视口区域if (isIntersecting) {el.src binding.value;}});},
});一个指令定义对象可以提供多个钩子函数比如 mounted、updated、unmounted 等我们使用mounted也就是在节点挂载完成后调用。指令的钩子有两个主要的参数el和binding。el是指令绑定到的元素binding中使用最多的是value即传递给指令的值例如在 v-lazy“imgSrc” 中值是 imgSrc对应的真实图片地址。
然后使用useIntersectionObserver函数它的两个参数一个是需要监听的元素另一个是回调函数参数值isIntersecting为一个布尔值用来判断当前监听元素是否进入视口区域如果进入视口区域那么我们就可以将图片的真实url赋值给图片的src。
其实上述代码还有不完善的地方首先是重复监听的问题可以进行console调试一下
useIntersectionObserver(el, ([{ isIntersecting }]) {console.log(isIntersecting);//测试if (isIntersecting) {el.src binding.value;}
});此时的效果如下图所示 从上图可以看到往上滚动监听过的图片会重复监听这是我们不想要的会造成性能浪费。
解决思路在监听的图片第一次完成加载后就停止监听。可以利用useIntersectionObserver函数提供的stop方法修改后的代码如下
app.directive(lazy, {mounted(el, binding) {const { stop } useIntersectionObserver(el, ([{ isIntersecting }]) {console.log(isIntersecting);if (isIntersecting) {el.src binding.value;//在监听的图片第一次完成加载后就停止监听stop();}});},
});完善后的效果如下解决了重复监听问题。 我们还可以设置一个默认图片当图片还没加载完成时就显示默认图片。
app.directive(lazy, {mounted(el, binding) {el.src /assets/images/default.png; // 使用默认图片const { stop } useIntersectionObserver(el, ([{ isIntersecting }]) {if (isIntersecting) {el.src binding.value;//在监听的图片第一次完成加载后就停止监听stop();}});},
});此时还存在着的一个问题是当前注册了一个全局的自定义指令所有的代码逻辑全写在入口文件中这样会造成代码的臃肿。
解决思路拆分代码通过插件的方法把懒加载指令封装为插件main.js入口文件只需负责注册插件即可。
src下新建directive/index.js文件专门存放自定义的插件把代码逻辑进行转移。
// src/directive/index.js
import { useIntersectionObserver } from vueuse/core;
// 封装插件
export const lazyPlugin {install(app) {app.directive(lazy, {mounted(el, binding) {el.src /assets/images/default.png; const { stop } useIntersectionObserver(el, ([{ isIntersecting }]) {if (isIntersecting) {el.src binding.value;stop();}});},});},
};然后在main.js中注册插件
import { createApp } from vue;
import App from ./App.vue;
import { lazyPlugin } from ./directive;const app createApp(App);
//注册插件
app.use(lazyPlugin);
app.mount(#app);定义插件可以参考Vue官网。通常一个 Vue3 的插件会暴露 install 函数当 app 实例 use 该插件时就会执行该函数。然后在 install 函数内部通过 app.directive 去注册一个全局指令这样就可以在组件中使用它们了。
现在的效果就和一开始介绍的效果一致了。
2.2 使用IntersectionObserver
其实查看vue3-lazy源码和useIntersectionObserver源码会发现它们使用的就是原生IntersectionObserver api。那么接下来我们也可以使用这个api来实现一个自定义的懒加载指令。
MDNIntersectionObserver 提供了一种异步观察目标元素与其祖先元素或顶级文档视口交叉状态的方法。当它被创建时其被配置为监听根中一段给定比例的可见区域。当其监听到目标元素的可见部分的比例超过了一个或多个阈值threshold时会执行指定的回调函数。
简单来说就是IntersectionObserver可以来判断图片是否进入可视区。
它对应的回调函数的参数 entries是 IntersectionObserverEntry 对象数组。当观测的元素可见比例超过指定阈值时就会执行该回调函数默认阈值为 0表示目标元素刚进入根元素可见范围时触发回调函数对 entries 进行遍历拿到每一个 entry然后判断 entry.isIntersecting 是否为 true如果是则说明 entry 对象对应的 DOM 元素进入了可视区。
具体代码如下
// src/directive/index.js
import defaultImg from /assets/images/default.png;
//定义一个数组用来存储尚未加载的图片
let imgsList [];//加载图片
function loadingImg(imgDOM) {//获得图片的srclet imgSrc imgsList.filter((item) item.el imgDOM)[0].src;//新建Image对象实例来代替当前图片的加载图片加载完毕就会触发onload事件替换img元素的src属性const img new Image();img.src imgSrc; img.onload function () {// 当图片加载完成之后 替换img元素的src属性imgDOM.src imgSrc;};//将已加载好的图片从数组中删除imgsList imgsList.filter((item) item.el ! imgDOM);
}const io new IntersectionObserver((entries) {entries.forEach((item) {// isIntersecting属性判断目标元素当前是否可见if (item.isIntersecting) {//加载图片加载完后停止监听loadingImg(item.target);io.unobserve(item.target); }});
});export const lazyPlugin {install(app) {app.directive(lazy, {mounted(el, binding) {el.src defaultImg; // 使用默认图片io.observe(el); //监听图片imgsList.push({ el: el, src: binding.value }); //数组中加入当前图片},beforeUnmount(el) {//某个img元素解绑时停止监听从数组中删除io.unobserve(el);imgsList imgsList.filter((item) item.el ! el);},});},
};主要思路就是定义一个数组用来存储尚未加载的图片observe方法对每个图片进行监听如果当前图片在可视区域就加载图片并且从数组中删除图片然后unobserve停止监听。
最后依然需要在main.js中注册插件即可使用v-lazy自定义指令。
参考资料 https://www.npmjs.com/package/vue3-lazyload https://cn.vuejs.org/guide/reusability/custom-directives.html https://cn.vuejs.org/guide/reusability/plugins.html https://www.vueusejs.com/core/useIntersectionObserver/ https://developer.mozilla.org/zh-CN/docs/Web/API/IntersectionObserver
好了以上就是本文的全部内容如有问题欢迎指出