图片懒加载
一、为什么需要懒加载
随着互联网技术发展,各类网站基本都已配载大量丰富多彩的图片,但如果寄希望于把所有图片一次性加载完成,那对于用户体验来说将是灾难性
的。
目前业界较为推崇的方法是懒加载
,简单来说,就是设置在用户可视区之外的图片默认不加载
,当图片随着用户的滚动操作进入了可显范围时,则加载显示图片。
话不多说,直接上代码。
二、JavaScript原生实现
使用 intersectionObserver()
const images = document.querySelectorAll('img') // 获取所有图片标签元素
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
// 判断当前元素是否可见
if (entry.isIntersecting) {
// 创建一个自定义属性data-src存放真正要显示的图片路径,原本img自带的src放一张默认图片
const img = entry.target
const data_src = img.getAttribute('data-src')
img.setAttribute('src', data_src)
// 解除观察,有几张图片就触发几次
observer.unobserve(img)
}
})
}, { threshold: 0.01 }) // 设置触发加载时的视图交叉比例
images.forEach(image => {
// 对每一个图片对象进行观察
observer.observe(image)
})
三、Vue2 自定义指令实现
在 main.js 中设置全局自定义指令,命名为 lazy,实际使用时则为 v-lazy
// 定义懒加载图片或者文件等,自定义指令
Vue.directive('lazy', (el, binding) => {
let oldSrc = el.src //保存旧的src,方便后期渲染时候赋值src真实路径
el.src = "" //将渲染的src赋为空,则不会渲染图片出来
let observer = new IntersectionObserver(([{ isIntersecting }]) => { // 调用方法得到该elDOM元素是否处于可视区域
if (isIntersecting) { //回调是否处于可视区域,true or false
el.src = oldSrc //如果处于可视区域额,将最开始保存的真实路径赋予DOM元素渲染
observer.unobserve(el) // 只需要监听一次即可,第二次滑动到可视区域时候不在监听
}
}, { threshold: 0 }) // 设置阈值
observer.observe(el) // 调用方法
})
四、Vue3 自定义指令实现
vue3 的指令拥有的钩子函数和组件的一样,使用指令的DOM是否创建好,钩子函数: mounted
export default {
install (app) {
// 定义指令
defineDirective(app)
}
}
// 定义指令
const defineDirective = (app) => {
// 图片懒加载
app.directive('lazy', {
// vue2 监听使用指令的DOM是否创建好 钩子函数: inserted
// vue3 的指令拥有的钩子函数和组件的一样,使用指令的DOM是否创建好,钩子函数: mounted
mounted (el, binding) {
// 创建一个观察对象,来观察当前使用指令的元素
const observer = new IntersectionObserver(([{ isIntersecting }]) => {
if (isIntersecting) {
console.log('您已进入一级战备状态')
// 停止观察
observer.unobserve(el)
// 加载失败时,设置默认展示图片
el.onerror = () => {
el.src = defaultImg
}
// 把指令的值设置给el的src属性 bingding.value就是指令的值
el.src = binding.value
}
}, { threshold: 0 })
observer.observe(el)
}
})
}
兼容性
目前基本已经支持所有浏览器,无需担忧。
总结
本文后续还将增加scroll和Vue3的useIntersectionObserver插件等方法。