1.原理
- 标签传入的url地址临时保存在data-src属性,src指定默认图片
- 判断方法1:通过IntersectionObserver 判断是否图片在当前浏览器可视区域内
- 判断方法2:通过监听滚动事件,实时通过 getBoundingClientRect() 获取当前的top 与bottom判断是否在浏览器可视区域内
- 当在可视区域内,把data-src的url信息赋值给 真正显示的src,并且移除data-src 属性
注意:
- 这里的right是按右边距离屏幕最左边计算,
- 这里的bottom 是按低边距离屏幕最上边计算
2.代码实现
const LazyLoad = {
// install方法
install(Vue, options) {
const defaultSrc = options.default
Vue.directive('lazy', {
bind(el, binding) {
LazyLoad.init(el, binding.value, defaultSrc)
},
inserted(el) {
if (IntersectionObserver) {
LazyLoad.observe(el)
} else {
LazyLoad.listenerScroll(el)
}
},
})
},
// 初始化
init(el, val, def) {
el.setAttribute('data-src', val)
el.setAttribute('src', def)
},
// 利用IntersectionObserver监听el
observe(el) {
var io = new IntersectionObserver((entries) => {
const realSrc = el.dataset.src
if (entries[0].isIntersecting) {
if (realSrc) {
el.src = realSrc
el.removeAttribute('data-src')
}
}
})
io.observe(el)
},
// 监听scroll事件
listenerScroll(el) {
const handler = LazyLoad.throttle(LazyLoad.load, 300) //定义节流的方法句柄
LazyLoad.load(el) //第一次自动执行
window.addEventListener('scroll', () => { //每次滚动都执行
//使用节流方法防止多次触发
handler(el)
})
},
// 加载真实图片
load(el) {
const windowHeight = document.documentElement.clientHeight
const elTop = el.getBoundingClientRect().top
const elBtm = el.getBoundingClientRect().bottom
const realSrc = el.dataset.src
if (elTop - windowHeight < 0 && elBtm > 0) {
if (realSrc) {
el.src = realSrc
el.removeAttribute('data-src')
}
}
},
// 节流
throttle(fn, delay) {
let timer
let prevTime
return function (...args) {
const currTime = Date.now()
const context = this
if (!prevTime) prevTime = currTime
clearTimeout(timer)
if (currTime - prevTime > delay) {
prevTime = currTime
fn.apply(context, args)
clearTimeout(timer)
return
}
timer = setTimeout(function () {
prevTime = Date.now()
timer = null
fn.apply(context, args)
}, delay)
}
},
}
export default LazyLoad
//使用方式
<img v-LazyLoad="xxx.jpg" />