vue-lazy
图片懒加载自定义指令实现
intersectionObsever
利用 entry.isIntersecting
方法
new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
ImageManager
export default class ImageManager {
el: HTMLElement;
parent: HTMLElement | Window;
src: string;
error: string;
loading: string;
cache: Set<string>;
state: State;
}
// types目录
export enum State {
loading,
loaded,
error,
}
// 初始化状态机,设置为loading
constructor (options: ImageManagerOptions) {
this.el = options.el
this.parent = options.parent
this.src = options.src
this.error = options.error
this.loading = options.loading
this.cache = options.cache
this.state = State.loading
this.render(this.loading)
}
// 强制渲染,loading预加载图必须强制渲染
// 通过在标签上添加src属性
private render (src: string): void {
this.el.setAttribute('src', src)
}
插件本体
import Lazy from "./core/lazy";
const lazyPlugin = {
install(app: App, options: LazyOptions) {
const lazy = new Lazy(options);
// 先安装插件,然后在app上增加自定义指令
app.directive("lazy", {
// 由于mounted设置方法会this丢 失,必须要绑定this
mounted: lazy.add.bind(lazy),
updated: lazy.update.bind(lazy),
unmounted: lazy.update.bind(lazy),
});
},
};
export default lazyPlugin;
//./types,在插件安装时默认好错误链接和加载链接
export interface LazyOptions {
error?: string;
loading?: string;
}
工具
找到最近的被设置了滚动的祖先元素 ,找不到返回 window
// ./helpers/dom
const style = (el: HTMLElement, prop: string): string => {
return getComputedStyle(el).getPropertyValue(prop)
}
const overflow = (el: HTMLElement): string => {
return style(el, 'overflow') + style(el, 'overflow-y') + style(el, 'overflow-x')
}
export function scrollParent (el: HTMLElement): HTMLElement | Window {
let parent = el
while (parent) {
if (parent === document.body || parent === document.documentElement) {
break
}
if (!parent.parentNode) {
break
}
if (/(scroll|auto)/.test(overflow(parent))) {
return parent
}
parent = parent.parentNode as HTMLElement
}
return window
}
自定义指令 mounted 周期
managerQueue: ImageManager[]
add (el: HTMLElement, binding: DirectiveBinding): void {
const src = binding.value
const parent = scrollParent(el)
const manager = new ImageManager({
el,
parent,
src,
error: this.error,
loading: this.loading,
cache: this.cache
})
// 每一张图片都有一个manager
this.managerQueue.push(manager)
// 如果浏览器不支持intersectionObserver
// 需要通过检测滚动事件
if (hasIntersectionObserver) {
this.observer!.observe(el)
} else {
this.addListenerTarget(parent)
this.addListenerTarget(window)
this.throttleLazyHandler()
}
}