vue-lazyload核心类详解:LazyContainer与LazyImage实现
一、核心类概述
vue-lazyload作为Vue.js的图片懒加载插件,其核心功能由多个类协同实现。其中src/lazy-container.js和src/lazy-image.js是实现懒加载的关键组件,它们分别负责容器级懒加载和图片懒加载的具体逻辑。
1.1 类关系图
二、LazyContainer容器懒加载实现
2.1 类定义与初始化
LazyContainer类在src/lazy-container.js中定义,主要用于处理容器内图片的批量懒加载。其构造函数接收el、binding、vnode和lazy实例等参数,并初始化队列和配置选项。
class LazyContainer {
constructor ({ el, binding, vnode, lazy }) {
this.el = null
this.vnode = vnode
this.binding = binding
this.options = {}
this.lazy = lazy
this._queue = []
this.update({ el, binding })
}
}
2.2 核心方法解析
2.2.1 update方法
update方法是LazyContainer的核心,它会根据配置选项选择器获取容器内所有图片元素,并为每个图片元素调用lazy.add方法进行懒加载注册。
update ({ el, binding }) {
this.el = el
this.options = assign({}, defaultOptions, binding.value)
const imgs = this.getImgs()
imgs.forEach(el => {
this.lazy.add(el, assign({}, this.binding, {
value: {
src: 'dataset' in el ? el.dataset.src : el.getAttribute('data-src'),
error: ('dataset' in el ? el.dataset.error : el.getAttribute('data-error')) || this.options.error,
loading: ('dataset' in el ? el.dataset.loading : el.getAttribute('data-loading')) || this.options.loading
}
}), this.vnode)
})
}
2.2.2 getImgs方法
getImgs方法通过querySelectorAll获取容器内符合选择器的图片元素,默认选择器为'img'。
getImgs () {
return ArrayFrom(this.el.querySelectorAll(this.options.selector))
}
2.2.3 clear方法
clear方法用于清除容器内所有图片的懒加载监听,在组件销毁时调用。
clear () {
const imgs = this.getImgs()
imgs.forEach(el => this.lazy.remove(el))
this.vnode = null
this.binding = null
this.lazy = null
}
三、LazyImage图片懒加载实现
3.1 组件定义与状态管理
LazyImage在src/lazy-image.js中定义为一个Vue组件,用于单个图片的懒加载处理。它通过data函数维护了图片的加载状态、尺寸信息和渲染地址等。
data () {
return {
el: null,
options: {
src: '',
error: '',
loading: '',
attempt: lazyManager.options.attempt
},
state: {
loaded: false,
error: false,
attempt: 0
},
rect: {},
renderSrc: ''
}
}
3.2 生命周期与懒加载触发
3.2.1 初始化与挂载
在created钩子中初始化图片配置,mounted钩子中获取DOM元素并注册到懒加载管理器。
created () {
this.init()
this.renderSrc = this.options.loading
},
mounted () {
this.el = this.$el
lazyManager.addLazyBox(this)
lazyManager.lazyLoadHandler()
}
3.2.2 视图检查与加载
checkInView方法通过getBoundingClientRect检查图片是否进入视口,load方法负责图片加载逻辑,包含重试机制。
checkInView () {
this.getRect()
return inBrowser &&
(this.rect.top < window.innerHeight * lazyManager.options.preLoad && this.rect.bottom > 0) &&
(this.rect.left < window.innerWidth * lazyManager.options.preLoad && this.rect.right > 0)
},
load (onFinish = noop) {
if ((this.state.attempt > this.options.attempt - 1) && this.state.error) {
if (!lazyManager.options.silent) console.log(`VueLazyload log: ${this.options.src} tried too more than ${this.options.attempt} times`)
onFinish()
return
}
const src = this.options.src
loadImageAsync({ src }, ({ src }) => {
this.renderSrc = src
this.state.loaded = true
}, e => {
this.state.attempt++
this.renderSrc = this.options.error
this.state.error = true
})
}
四、关键工具函数支持
LazyContainer和LazyImage的实现依赖于src/util.js中的多个工具函数,例如:
- loadImageAsync: 异步加载图片,处理加载成功和失败的回调
- inBrowser: 检测是否在浏览器环境
- throttle: 节流函数,优化滚动事件性能
- getBestSelectionFromSrcset: 根据容器宽度和设备像素比选择合适的图片源
五、与Lazy核心类的协作
LazyContainer和LazyImage都依赖于src/lazy.js中定义的Lazy类进行统一管理。Lazy类维护了一个ListenerQueue队列,负责监听元素是否进入视口,并触发相应的加载逻辑。
// Lazy类核心方法
_lazyLoadHandler () {
const freeList = []
this.ListenerQueue.forEach((listener, index) => {
if (!listener.el || !listener.el.parentNode) {
freeList.push(listener)
}
const catIn = listener.checkInView()
if (!catIn) return
listener.load()
})
freeList.forEach(item => {
remove(this.ListenerQueue, item)
item.$destroy()
})
}
六、使用场景与最佳实践
6.1 LazyContainer适用场景
- 长列表图片懒加载,如商品列表
- 动态生成的图片容器
- 需要自定义选择器的图片集合
6.2 LazyImage适用场景
- 单个图片懒加载
- 需要精细控制加载状态的图片
- 包含加载中、错误状态显示的图片
七、总结与展望
LazyContainer和LazyImage作为vue-lazyload的核心组件,分别解决了容器级和单图片级的懒加载问题。通过与Lazy类的协作,实现了高效的图片懒加载机制。未来可以考虑进一步优化以下方面:
- 增加对视频等其他媒体类型的懒加载支持
- 优化交叉观察器(IntersectionObserver)的使用,提高性能
- 增加更多的加载状态回调,提供更灵活的定制能力
完整的源码实现可参考项目中的src/lazy-container.js和src/lazy-image.js文件。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



