背景:如果不使用懒加载,页面加载后,列表内所有的图片均会被浏览器加载,消耗资源,用户体验非常差,懒加载是性能优化的基础之一。
想做的就是让图片按需加载,触发滚动时遍历图片检测图片位置,若在可视区内则显示。
另外了解一下:
window.onload()--等待网页中所有内容加载完毕之后(包括图片)才能执行。
jQuery中$(docoment).ready --在网页所有的DOM结构绘制完毕就执行,可能DOM元素关联的东西并没有加载完。
1.改变图片的src(见4的优化)
监听最外层div的滚动事件,触发滚动时遍历图片检测图片位置,若在可视区则显示。
// template:
<div @scroll="lazyLoad" ref="lazy">
<img v-for="(src, index) in imgs" src="##" :dataSrc="src" :key="index">
<!--more img-->
</div>
// methods:
loadImg () {
var img = this.$ref.lazy.getElementsByClassName("lazyImg");
//已滚动高度+可视区高度
var top = this.$refs.lazy.scrollTop + this.$refs.lazy.clientHeight;
for(var i=0 ; i<img.length; i++){
if(img[i].offsetTop <= top) {
img[i].src = img[i].getAttribute('data-src')
}
}
}
lazyLoad () {
this.LoadImg()
}
图片的src属性为空,使用data-src属性写上需要加载的图片的路径url,在懒加载的代码中,将src属性的值替换成对应的data-src。
2. vue中使用vue-lazyload
2.1 安装
npm -i vue-lazyload -S
或者引入CDN: https://unpkg.com/vue-lazyload/vue-lazyload.js
2.2 使用
main.js
import Vue from 'vue'
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)
// or with options
Vue.use(VueLazyload, {
preLoad: 1.3,
error: 'dist/error.png',
loading: 'dist/loading.gif' //项目存放图片的路径
attempt: 1
})
template:
<ul>
<li v-for="img in list">
<img v-lazy="img.src">
</li>
</ul>
use v-lazy-container work with raw HTML and custom error and loading placeholder image
<div v-lazy-container="{ selector: 'img', error: 'xxx.jpg', loading: 'xxx.jpg' }">
<img data-src="//domain.com/img1.jpg">
<img data-src="//domain.com/img2.jpg">
<img data-src="//domain.com/img3.jpg">
</div>
2.3 了解属性:
key | description | default | options |
---|---|---|---|
preLoad | 预载的高度比例 | 1.3 | Number |
error | 加载失败时src | 'data-src' | String |
loading | 加载图片时src | 'data-src' | String |
attempt | 常识次数 | 3 | Number |
listenEvents | 监听的事件 | ['scroll', 'wheel', 'mousewheel', 'resize', 'animationend', 'transitionend', 'touchmove'] | |
adapter | 动态修改element属性 | { } | |
filter | 图像的侦听器过滤器 | { } | |
lazyComponent | 延迟加载组件 | false | |
dispatchEvent | 触发dom事件 | false | Boolean |
throttleWait | 200 | Number | |
observer | false | Boolean | |
observerOptions | { rootMargin: '0px', threshold: 0.1 } | ||
silent | true | Boolean |
2.4 CSS state
<img src="imgUrl" lazy="loading">
<img src="imgUrl" lazy="loaded">
<img src="imgUrl" lazy="error">
<style>
img[lazy=loading] {
/*your style here*/
}
img[lazy=error] {
/*your style here*/
}
.yourclass[lazy=loading] {
/*your style here*/
}
</style>
2.5 效果图
3. 拓展:各种宽高
页可见区域宽: document.body.clientWidth;
网页可见区域高: document.body.clientHeight;
网页可见区域宽: document.body.offsetWidth (包括边线的宽);
网页可见区域高: document.body.offsetHeight (包括边线的宽);
网页正文全文宽: document.body.scrollWidth;
网页正文全文高: document.body.scrollHeight;
网页被卷去的高: document.body.scrollTop;
网页被卷去的左: document.body.scrollLeft;
网页正文部分上: window.screenTop;
网页正文部分左: window.screenLeft;
屏幕分辨率的高: window.screen.height;
屏幕分辨率的宽: window.screen.width;
屏幕可用工作区高度: window.screen.availHeight;
4.优化1
监听滚动事件,在滚动过程会不断触发lazyLoad对图片做一个遍历并判断,那么就会做无数次for循环,修改一次src会发送一个请求,在滚动的时候for循环每次都从头判断并修改src请求图片,那么请求次数可想而知。
函数防抖
如果在滚动过程中不断触发遍历并判断图片是否在可视区的监听事件,会耗费很大的性能,这里采用函数防抖:当用户停止滚动时统一遍历判断图片位置
debounce(fn) {
// 函数防抖:用户停止操作之后触发
clearTimeout(this.timer);
this.timer = setTimeout(() => {
fn();
}, 1000);
}
// 将加载图片的方法放在debounce中
lazyLoad() {
this.debounce(this.loadImg);
}
当用户滚动页面时,松开手才会执行loadImg来遍历判断图片位置。
又出现了一个问题:如果用户在滚动时从页面底部上拉到顶部一直没有松手,那么在这期间都不会执行loadImg,这意味着页面的图片都不会显示,非常影响用户体验
防抖优化
若用户上拉高度大于500px 那就自动加载一次可视区内图片,当用户下拉时并不需要执行。
lazyLoad () {
// 如果上拉距离大于500px则自动加载
if(this.$refs.lazy.scrollTop - this.oldScrollTop > 500) {
this.loadImg();
this.oldScrollTop = this.$refs.lazy.scrollTop;
} else if(this.$refs.lazy.scrollTop - this.oldScrollTop < 0) { // 如果向下拉则不做操作
return ;
} else { // 如果向下拉但小于500px则防抖加载
this.debounce(this.loadImg);
}
}