-
Notifications
You must be signed in to change notification settings - Fork 184
Open
Labels
Description
基础(必会)
参考链接:Intersection Observer API - Web API | MDN
思路
- 创建
LazyLoadImage
类,全局只实例化一次,执行init方法 - 每个img标签被创建时,自动将添加到观察者队列
- 没进入视窗时,src被赋予了loading图片地址,真实的地址被保存在
data-src
属性中 - 进入视窗后,从
data-src
属性中取出真正的地址,赋予给src
属性,完成加载
- 没进入视窗时,src被赋予了loading图片地址,真实的地址被保存在
- 加载完图片后,把该img标签从观察者队列中删除,不再被观察
创建一个全局的LazyLoadImage
类
// 引入polyfill,解决兼容性问题
import 'intersection-observer';
IntersectionObserver.prototype['THROTTLE_TIMEOUT'] = 300;
const DefaultLoadingImage = '默认loading图片'
export default class LazyLoadImage {
_observer: IntersectionObserver | null;
_loadingImage: string;
constructor(option: object = {}) {
this._observer = null;
// @ts-ignore
this._loadingImage = option.loading || DefaultLoadingImage;
this.init();
}
init() {
this._observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
// 触发进入视窗条件,替换真正的图片链接到src属性上
if (entry.isIntersecting) {
// @ts-ignore
const url = entry.target.getAttribute('data-src');
// @ts-ignore
entry.target.setAttribute('src', url);
entry.target.setAttribute('data-src', '');
// 替换真正的线上地址后,取消对该元素的观察
this._observer && this._observer.unobserve(entry.target);
}
})
}, {
root: null,
rootMargin: "500px 200px 1000px 200px", // 扩大视窗范围,提前加载
threshold: 0.1
})
}
// 让每个img标签自行调用add方法,把自己添加到观察者队列中
add(entry: any) {
this._observer && this._observer.observe(entry.el);
}
}
封装vue指令
// 全局只实例化一个类,实例执行init方法自己创建观察者队列
const lazyload = new LazyLoadImage();
// 让每个img标签自行调用add方法,把自己添加到观察者队列中
// 用法: <img v-lazy="图片地址" />
Vue.directive('lazy', {
bind(el, binding) {
el.setAttribute('data-src', binding.value);
el.setAttribute('src', lazyload._loadingImage);
lazyload.add({el: el, val: binding.value});
}
})
klren0312