「~实践与源码 ~」
* 学习进阶方式 💪
- 基础知识要夯实;
- 原理源码要深入;
- 深度广度要扩展;
vue-lazyload 解决了什么问题?(项目常用)
可以想象一个网页打开有成百上千的图片需要加载,页面会变得非常的卡顿,此时如果只是可视区域的图片加载,其他的图片可以暂时有一个占位loading图,等滚动它们到可视区域时再去请求真实图片并且替换就好了。很好,vue-lazyload插件就是解决此类问题的。
vue-lazyload 图片懒加载- 实践
一、安装插件
vue-lazyload官网npm配置地址(重要)
https://www.npmjs.com/package/vue-lazyload
- npm i vue-lazyload --save
二、配置插件
在main.js 文件中 引入 vue-lazyload 的插件。 (全局)
1、最外层static目录下的图片引用
- import VueLazyLoad from 'vue-lazyload';
- // 最外层static目录下的图片引用
- Vue.use(VueLazyLoad, {
- error: '/static/images/defaultAvatar.png', // 此处是图片加载失败时候 显示的图片
- loading: '/static/images/defaultAvatar.png', // 此处是图片加载中 显示的图片
- attempt: 1, // 加载一屏图片
- preLoad: 1, // 失败尝试次数
- });
2、src下的assets目录下的图片
- import VueLazyLoad from 'vue-lazyload';
- // src下的assets目录下的图片
- Vue.use(VueLazyLoad, {
- error: require('common/assets/defaultAvatar.png'), // 此处是图片加载失败时候 显示的图片
- loading: require('common/assets/defaultAvatar.png'), // 此处是图片加载中 显示的图片
- attempt: 1, // 加载一屏图片
- preLoad: 1, // 失败尝试次数
- });
*项目使用遇到问题,说明:
import VueLazyLoad from 'vue-lazyload';
报错:Absolute imports should come before relative imports.
原因:主要是引入文件的位置问题。
三、使用插件
只需要在动态请求img 路径 把原本的 :scr="url", 替换为 v-lazy="url" 接下来,再去看看效果实例。
- <img v-lazy="talent.cover_url" :key="talent.cover_url" class="picsrc" >
说明:
选项卡模式的图片列表,每次点击切换时候,会请求不同数量,不同的图片内容。然而发现 列表中的前几个图片,无论怎么来回切换,每次都显示最开始的图片。
这个时候 解决办法是 在img 里面 加上 :key="url" 就可以解决这个bug;
四、项目需求:不同模块选择不同的图片 (局部)
vue-lazyload插件如何做不同模块选择不同的loading图片(通过样式进行设置)
- import VueLazyLoad from 'vue-lazyload';
- // 最外层static目录下的图片引用
- Vue.use(VueLazyLoad, {
- // error: '/static/images/defaultAvatar.png', // 此处是图片加载失败时候 显示的图片
- // loading: '/static/images/defaultAvatar.png', // 此处是图片加载中 显示的图片
- // attempt: 1, // 加载一屏图片
- // preLoad: 1, // 失败尝试次数
- });
- // 图片加载中、加载结束、或者加载错误三种状态
- <style>
- .yourclass[lazy=loading] {
- /*your style here*/
- }
- .yourclass[lazy=error] {
- /*your style here*/
- }
- .yourclass[lazy=loaded] {
- /*your style here*/
- }
- </style>
注意:全局与局部是单独设置的,全局的优先级高。
五、构造函数选项
vue-lazyload 图片懒加载- 源码
一、原理剖析
lazyload的主要流程的流程图
原理简述:
1)vue-lazyload是通过指令的方式实现的,定义的指令是v-lazy指令;
2)指令被bind时会创建一个listener,并将其添加到listener queue里面, 并且搜索target dom节点,为其注册dom事件(如scroll事件);
3)上面的dom事件回调中,会遍历 listener queue里的listener,判断此listener绑定的dom是否处于页面中perload的位置,如果处于则加载异步加载当前图片的资源;
4)同时listener会在当前图片加载的过程的loading,loaded,error三种状态触发当前dom渲染的函数,分别渲染三种状态下dom的内容;
二、源码解析:
1、在组件install安装时,调用LazyClass返回了一个class对象,然后创建了一个class实例。
2、其核心是lazyLoadHandler()函数,是经过节流函数处理的图片加载的入口函数。
- this.lazyLoadHandler = throttle(() => {
- let catIn = false
- this.ListenerQueue.forEach(listener => {
- if (listener.state.loaded) return
- catIn = listener.checkInView()
- catIn && listener.load()
- })
- }, 200)
- checkInView () {
- this.getRect() // 调用dom的getBoundingClientRect()
- return (this.rect.top < window.innerHeight * this.options.preLoad && this.rect.bottom > this.options.preLoadTop) &&
- (this.rect.left < window.innerWidth * this.options.preLoad && this.rect.right > 0)
- // 判断dom的顶部是否到了preload的位置,判断dom的底部是否到达了preload的位置,X轴同理。
- }
3、主要操作:找到对应的target(用于注册dom事件的dom节点;比如:页面滚动的dom节点),为其注册dom事件;为当前dom创建Listenr并添加到listener queue中。最后用lazyLoadHandler()函数,加载图片。
4、当满足条件,调用load()函数异步加载图片。
- load () {
- // 如果当前尝试加载图片的次数大于指定的次数, 并且当前状态还是错误的, 停止加载动作
- if ((this.attempt > this.options.attempt - 1) && this.state.error) {
- if (!this.options.silent) console.log('error end')
- return
- }
- if (this.state.loaded || imageCache[this.src]) { //如果已缓存
- return this.render('loaded', true) // 使用缓存渲染图片
- }
- this.render('loading', false) // 调用lazy中的 elRender()函数, 用户切换img的src显示数据,并触发相应的状态的回调函数
- this.attempt++ // 尝试次数累加
- this.record('loadStart') // 记录当前状态的时间
- // 异步加载图片, 使用Image对象实现
- loadImageAsync({
- src: this.src
- }, data => {
- this.naturalHeight = data.naturalHeight
- this.naturalWidth = data.naturalWidth
- this.state.loaded = true
- this.state.error = false
- this.record('loadEnd')
- this.render('loaded', false) // 渲染 loaded状态的 dom的内容
- imageCache[this.src] = 1 // 当前图片缓存在浏览器里面了
- }, err => {
- this.state.error = true
- this.state.loaded = false
- this.render('error', false)
- })
- }
5、loadImageAsync异步加载图片方法,通过image对象实现的网络请求。
- const loadImageAsync = (item, resolve, reject) => {
- let image = new Image()
- image.src = item.src
- image.onload = function () {
- resolve({
- naturalHeight: image.naturalHeight, // 图片的 实际高度
- naturalWidth: image.naturalWidth,
- src: image.src
- })
- }
- image.onerror = function (e) {
- reject(e)
- }
- }
6、lazy class的update()函数,也就是v-lazy指令绑定的数据发生改变的时候出发的回调函数。
- update (el, binding) { // 获取当前dom绑定的 图片src的数据, 如果当前dom执行过load过程, 重置当前dom的图片数据和状态
- let { src, loading, error } = this.valueFormatter(binding.value) // 当前绑定的value是 obj, 从中选取{src, loading, error}; 是string, 则用作src
- // 找到当前dom绑定的listener
- const exist = find(this.ListenerQueue, item => item.el === el)
- // 更新listener的状态和状态对应的图片资源
- exist && exist.update({
- src,
- loading,
- error
- })
- this.lazyLoadHandler()
- Vue.nextTick(() => this.lazyLoadHandler())
- }
【编辑推荐】