1)图片懒加载
是常见的用于在页面滚动时动态加载图片,而不是在页面加载时一次性加载所有图片。性能优化必备提高页面加载速度的手段,特别是在包含大量图片的网站上。
图片懒加载的原理,其实就是,当图片出现在视口内时,进行图片的加载。
市场上也有成熟的第三方库可以帮助我们实现图片懒加载,如 Vue Lazyload 或 vue3-lazy。
不过在这里,我通过自己的理解,使用浏览器 API——Intersection Observer 实现图片懒加载的自定义指令。
2)看图说话
3)自定义指令(代码中有详解讲解IntersectionObserver用法)
// src/directives/layload/index.js
// 图片加载中时占位
import loadingImg from '../../asset/layload/loadingImg.gif'
// 图片加载错误时占位
import errorImg from '../../asset/layload/errorImg.png'
export default {
mounted(el, binding) {
el.src = loadingImg
// IntersectionObserver 接口提供了一种异步观察目标元素
// 与其祖先元素或顶级文档视口(viewport)交叉状态的方法。
el.Intersection = new IntersectionObserver((entries) => {
// 如果交叉,则背景图片替换成绑定图片
if (entries[0].isIntersecting) {
el.src = binding.value.src
// 加载成功
el.onload = (res) => {
console.log('加载成功', res)
};
// 加载失败了需要做一个错误图片的占位
el.onerror = (err) => {
console.log('加载失败', err);
el.src = errorImg
}
}
})
el.Intersection.observe(el)
},
unmounted(el, binding) {
el.Intersection.unobserve(el)
}
}
// directives/index.js
import layload from "./layload"
// 自定义指令对象,用于遍历注册
const directives = {
layload
}
// 批量注册指令并暴露到main.js中去便于注册
export default {
install(app) {
Object.keys(directives).forEach((key) => {
app.directive(key, directives[key])
})
}
}
// main.js中引入以下代码
// 引入并使用自定义指令
import directive from './directives'
app.use(directive);
<!-- 自定义指令 -->
<template>
<h4>图片懒加载自定义指令</h4>
<div class="imgBox">
<img class="image" v-layload="img" v-for="img in imgList" :key="img">
</div>
</template>
<script setup>
import { ref } from 'vue'
const imgList = [
{
src: "http://ashuai.work:10000/imgSrc/html.png",
},
{
src: "http://ashuai.work:10000/imgSrc/css.png",
},
{
src: "http://ashuai.work:10000/imgSrc/js.png",
},
{
src: "http://ashuai.work:10000/imgSrc/nodejs.png",
},
{
src: "http://ashuai.work:10000/imgSrc/webpack.png",
},
{
src: "http://ashuai.work:10000/imgSrc/vue.png",
},
{
src: "http://ashuai.work:10000/imgSrc/react.png",
},
{
src: "http://ashuai.work:10000/imgSrc/angular.png",
},
{
src: "http://ashuai.work:10000/imgSrc/ie.png",
},
{
src: "http://ashuai.work:10000/imgSrc/chrome.png",
},
{
src: "http://ashuai.work:10000/imgSrc/firefox.png",
},
{
src: "http://ashuai.work:10000/imgSrc/safari.png",
},
{
src: "http://ashuai.work:10000/imgSrc/edge.png",
},
{
src: "http://ashuai.work:10000/imgSrc/http.png",
},
{
src: "http://ashuai.work:10000/imgSrc/uniapp.png",
},
{
src: "http://ashuai.work:10000/imgSrc/wx.png",
},
{
src: "http://ashuai.work:10000/imgSrc/leetcode.png",
},
{
src: "http://ashuai.work:10000/imgSrc/java.png",
},
{
src: "http://ashuai.work:10000/imgSrc/spring.png",
},
{
src: "http://ashuai.work:10000/imgSrc/mybatis.png",
},
{
src: "http://ashuai.work:10000/imgSrc/redis.png",
},
{
src: "http://ashuai.work:10000/imgSrc/mysql.png",
},
{
src: "http://ashuai.work:10000/imgSrc/oracle.png",
},
{
src: "占位",
}
]
const handleSizeChange = (val) => {
console.log(`${val} items per page`)
}
const handleCurrentChange = (val) => {
console.log(`current page: ${val}`)
}
</script>
<style scoped>
.demo-pagination-block+.demo-pagination-block {
margin-top: 10px;
}
.demo-pagination-block .demonstration {
margin-bottom: 16px;
}
.imgBox {
width: 100%;
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
}
.image {
width: 200px;
height: 200px;
}
</style>
很多问题有多种解决方案,深入探究,前进。
积跬步,至江河。加油ヾ(◍°∇°◍)ノ゙