介绍
为什么要有懒加载?
在一个网页中如果有很多张图片,那么用户初进这个页面的时候不必一次性把所有图片都加载出来,否则容易造成卡顿和浪费。应该是,用户的视图页面滑到该图片的位置,然后再把该图片加载出来。
前置知识
自定义指令
在 Vue.js 中,app.directive
是用于注册自定义指令的 API。自定义指令允许你在组件的模板中实现特定的功能或行为,这些功能或行为通常是 DOM 操作。
1. 什么是自定义指令?
自定义指令是一种可以在模板中使用的功能,通常以 v-
开头。例如,v-model
和 v-bind
是内置指令。通过创建自定义指令,你可以扩展 Vue 的功能。
2. 使用 app.directive
在 Vue 3 中,使用 app.directive
注册自定义指令的基本语法如下:
javascript">const app = Vue.createApp({});app.directive('directive-name', {// 指令的钩子函数mounted(el, binding) {// 在元素被挂载时调用},updated(el, binding) {// 在元素更新时调用},unmounted(el) {// 在元素卸载时调用}
});
3. 示例
以下是一个简单的自定义指令示例,创建一个 v-focus
指令,使得绑定该指令的元素在页面加载时自动获得焦点:
javascript">const app = Vue.createApp({});app.directive('focus', {mounted(el) {el.focus(); // 元素挂载后自动获得焦点}
});app.component('my-component', {template: `<input v-focus placeholder="I will be focused on load" />`
});app.mount('#app');
4. 指令的钩子
常用的钩子函数包括:
created
: 指令被创建时调用。beforeMount
: 指令要被绑定到元素上之前调用。mounted
: 指令绑定到元素上之后调用。updated
: 被绑定的元素更新时调用。beforeUnmount
: 指令要被解绑之前调用。unmounted
: 指令解绑后调用。
总结
app.directive
: 用于注册自定义指令。- 自定义指令: 可以在模板中添加特定的功能,增强组件的交互性。
- 钩子函数: 提供不同生命周期阶段的操作机会。
VueUse
VueUse 是一个为 Vue.js 提供的实用工具库,旨在帮助开发者更高效地构建应用。它包含了一系列可复用的组合式 API(composables),使得在 Vue 应用中使用常见功能变得更加简单和快捷。
懒加载用到了useIntersectionObserver,作用是检测图片是否在视口内。
javascript"><script setup>
import { useIntersectionObserver } from '@vueuse/core'
import { ref } from 'vue'const target = ref(null)
const targetIsVisible = ref(false)const { stop } = useIntersectionObserver(target,([{ isIntersecting }], observerElement) => {targetIsVisible.value = isIntersecting},
)
</script><template><div ref="target"><h1>Hello world</h1></div>
</template>
例子
main.js
javascript">// 定义全局指令
app.directive('img-lazy', {mounted(el, binding) {// el: 指令绑定的那个元素 (即 img 元素)// binding: binding.value 指令等于号后面绑定的表达式的值 (图片 URL)console.log(el, binding.value); // 输出当前元素和绑定的图片 URLconst{stop} = useIntersectionObserver(el,([{ isIntersecting }]) => {console.log(isIntersecting); // 输出当前的可见性状态if (isIntersecting) { // 如果元素进入视口el.src = binding.value; // 将 img 元素的 src 属性设置为绑定的图片 URLstop();//停止监听,否则会重复请求}},);}
});
-
定义全局指令:
- 使用
app.directive
方法定义一个名为img-lazy
的指令。
- 使用
-
mounted 生命周期钩子:
- 当指令被绑定到元素时,会调用
mounted
钩子。这里的el
是指令绑定的 DOM 元素(在这个例子中是<img>
标签),binding
是一个对象,包含指令的相关信息。
- 当指令被绑定到元素时,会调用
-
输出调试信息:
console.log(el, binding.value)
会打印出当前被绑定的元素(el
)和指令传入的值(通常是图片的 URL)。
-
使用 Intersection Observer:
- 调用
useIntersectionObserver
函数来创建一个观察者,该观察者会监测el
(即图片元素)的可见性。 ([ { isIntersecting } ])
是解构赋值,从回调函数的参数中提取出isIntersecting
,它表示元素是否在视口内。
- 调用
-
判断元素是否在视口内:
- 如果
isIntersecting
为true
,意味着图片元素进入了可视区域。 - 此时,将
el.src
设置为binding.value
,即将图片的src
属性更新为指令绑定的 URL,从而加载图片。
- 如果
在别的组件
javascript"><img v-img-lazy="item.picture" alt="" />
解释
-
<img>
标签:- 这是一个 HTML 元素,用于显示图片。
-
指令
v-img-lazy
:- 这是你定义的自定义指令,名为
img-lazy
。通过前缀v-
来标识它是 Vue 的指令。 - 这里使用
v-img-lazy
是为了实现懒加载效果,使得图片在用户滚动到视口时才会被加载。
- 这是你定义的自定义指令,名为
-
item.picture
:- 这是绑定到指令的值,通常在 Vue 组件的数据中
item
是一个对象,picture
是该对象的一个属性,表示图片的 URL。 - 例如,如果
item
是{ picture: 'http://example.com/image.jpg' }
,那么item.picture
就是'http://example.com/image.jpg'
。
- 这是绑定到指令的值,通常在 Vue 组件的数据中
-
alt=""
属性:alt
属性用于提供替代文本,以便在图片无法加载或用户使用屏幕阅读器时显示。这是一个良好的无障碍设计实践。
整体流程
当这行代码渲染到页面时,以下步骤会发生:
-
指令初始化:
- 当 Vue 渲染这个
img
标签时,会调用v-img-lazy
指令的mounted
钩子。
- 当 Vue 渲染这个
-
传递值:
- 在
mounted
钩子中,el
是指这个<img>
元素,binding.value
将会是item.picture
的值(即图片的 URL)。
- 在
-
设置观察者:
- 使用
useIntersectionObserver
函数监测这个图片元素的可见性。
- 使用
-
懒加载逻辑:
- 当用户滚动页面,且
<img>
元素进入视口时,isIntersecting
会变为true
,此时指令会将<img>
的src
属性设置为item.picture
,从而加载图片。
- 当用户滚动页面,且
总结
简单来说,这段代码的目的是确保只有当用户滚动到 <img>
元素所在的位置时,浏览器才会请求并加载该图片,从而提高页面性能,减少初始加载时间。