这次我在项目中遇到同时加载多张图片,带宽瞬间大量消耗,造成页面卡顿。给图片懒加载,避开带宽峰值,提高页面加载速度。
封装懒加载使用到IntersectionObserver API
IntersectionObserver API提供了一种异步观察目标元素与其祖先元素或顶级文档视口(viewport)交叉状态的方法。其祖先元素或视口被称为根(root)。
const observer = new IntersectionObserver(callback, {
root: null, // 默认以视口为观察容器
rootMargin: '200px', // 计算交叉时添加到根边界盒的矩形偏移量,提前200px触发加载
threshold: 0.01 // 元素可见1%即触发
});
关于自定义指令
自定义指令主要是为了重用涉及普通元素的底层 DOM 访问的逻辑。一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数。
自定义指令的注册方式
局部注册,需要通过directives 选项注册
export default {
directives: {
// 在模板中启用 v-lazy
lazy: {
/* ... */
}
}
}
自定义组件的全局注册
Vue.directive('lazy',lazyLoad)
关于指令钩子
export default {
//首次绑定到元素时触发(适合初始化操作)
bind(el, binding) {},
// 元素插入父节点时触发(适合DOM相关操作)
inserted(el, binding) {},
// 所在组件VNode更新时触发
update(el, binding) {
// 当绑定值变化时会触发
if (binding.oldValue !== binding.value) {
// 可在此添加重新加载逻辑
}
},
// 所在组件及子组件VNode更新后
componentUpdated(el, binding) {
// 可用于处理子组件更新后的操作
},
//指令解绑时触发
unbind(el) {
// 应在此清理IntersectionObserver
// observer.disconnect()
}
}
指令钩子中使用的参数
el:指令绑定到的元素。这可以用于直接操作 DOM。
binding:一个对象,包含以下属性:
value:传递给指令的值。
instance:使用该指令的组件实例。
了解完前置知识,现在创建lazy.js文件,存放自定义指令
export default {
inserted(el, binding) {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
//访问组件实例
if (entry.isIntersecting) {
const img = new Image()
img.src = binding.value
img.onload = () => {
el.src = binding.value
el.classList.add('fade-in')
}
img.onerror = () => {
el.src = require('@/assets/error-img.png')
}
// 停止监听特定目标元素
observer.unobserve(el)
}
})
})
// 开始监听一个目标元素
observer.observe(el)
}
}
把懒加载自定义组件放全局,在main.js中注册
import lazyLoad from '@/directives/lazy.js'
Vue.directive('lazy',lazyLoad)
最后给图片使用 v-lazy指令
<img
v-lazy="imgSrc"
src="放base64图" />