在前端开发中,网页中图片的加载速度是影响网页流畅度的一个重要因素,提到前端性能优化中图片资源的优化,懒加载和预加载就不能不说。
预加载
实现功能:先加载图片资源,防止用户在刷网页的时候出现白屏的情况
预加载的核心要点如下:
- 图片等静态资源在使用之前的提前请求;
- 资源后续使用时可以从缓存中加载,提升用户体验;
- 页面展示的依赖关系维护(必需的资源加载完才可以展示页面,防止白屏等);
几个误区:
- 预加载不是为了减少页面加载时间
- 预加载只是提前加载除去首轮加载的图片以后要用到的图片,比如通过点击等事件才会用到的图片。
实现预加载主要有三个方法:
- html中img标签最初设置为display:none;或者放置div,为div加背景图,设置display:none;不需要任何js
<div class="wechart_pub" style="display: none;">
<img src="newWeb/images/official_download_qrcode.png"/>
</div>
<div class="wechart_pub" style="display: none;"></div>
- 单纯的js预加载图片
<div class="hidden">
<script type="text/javascript">
var images = new Array()
function preload() {
for (i = 0; i < preload.arguments.length; i++) {
images[i] = new Image()
images[i].src = preload.arguments[i]
}
}
preload(
"http://domain.tld/gallery/image-001.jpg",
"http://domain.tld/gallery/image-002.jpg",
"http://domain.tld/gallery/image-003.jpg"
)
</script>
</div>
- 使用XMLHttpRequest对象可以更加精细的控制预加载过程,缺点是无法跨域:
使用Ajax,比直接使用JavaScript,优越之处在于JavaScript和CSS的加载不会影响到当前页面。该方法简洁、高效。
window.onload = function() {
setTimeout(function() {
// XHR to request a JS and a CSS
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://domain.tld/preload.js');
xhr.send('');
xhr = new XMLHttpRequest();
xhr.open('GET', 'http://domain.tld/preload.css');
xhr.send('');
// preload image
new Image().src = "http://domain.tld/preload.png";
}, 1000);
};
懒加载
实现功能:能够按需加载,减轻服务器前端的压力。在一些图片非常多的网站中非常有用,当图片位置进入到可视区的时候才会被加载,这样对于含有很多 图片的比较长的网页来说,可以加载的更快,并且还能节省服务器带宽,用户体验好。
懒加载的要点如下:
- 图片进入可视区域之后请求图片资源;
- 对于电商等图片较多,页面很长的业务场景很适用;
- 可以减少无效资源的加载;
- 并发加载的资源过多会阻塞js的加载,影响网站的正常使用;
懒加载也就是延迟加载。
如何实现懒加载呢?要点就是html中图片的路径(这样就只需请求一次,俗称占位图),给一个data属性,里面存放图片真实地址,只有当图片出现在浏览器的可视区域内时,才设置图片正真的路径,让图片显示出来。这就是图片懒加载。
懒加载的实现步骤?
- 首先,不要将图片地址放到src属性中,而是放到其它属性(data-original)中。
- 页面加载完成后,根据scrollTop判断图片是否在用户的视野内,如果在,则将data-original属性中的值取出存放到src属性中。
- 在滚动事件中重复判断图片是否进入视野,如果进入,则将data-original属性中的值取出存放到src属性中。
懒加载实现代码
//懒加载代码实现
var viewHeight = document.documentElement.clientHeight // 可视区域的高度
function lazyload () {
// 获取所有要进行懒加载的图片
var eles = document.querySelectorAll('img[data-original][lazyload]')
Array.prototype.forEach.call(eles, function (item, index) {
var rect
if (item.dataset.original === '')
return
rect = item.getBoundingClientRect()
// 图片一进入可视区,动态加载
if (rect.bottom >= 0 && rect.top < viewHeight) {
!function () {
var img = new Image()
img.src = item.dataset.original
img.onload = function () {
item.src = img.src
}
item.removeAttribute('data-original')
item.removeAttribute('lazyload')
}()
}
})
}
// 首屏要人为的调用,否则刚进入页面不显示图片
lazyload()
document.addEventListener('scroll', lazyload)
相关的插件: lazyload
补充知识
- 屏幕可视窗口高度
//原生方法
window.innerHeight //标准浏览器及IE9+
|| document.documentElement.clientHeight //标准浏览器及低版本IE标准模式
|| document.body.clientHeight //低版本混杂模式
//jQuery方法
$(window).height();
- 浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离:
//原生方法
window.pagYoffset //标准浏览器及IE9+
|| document.documentElement.scrollTop //兼容ie低版本的标准模式
|| document.body.scrollTop //兼容混杂模式;
//jQuery方法
$(document).scrollTop();
- 获取元素的尺寸
$(elemnt).width() = elemnt.style.width;
$(elemnt).innerWidth() = elemnt.style.width+elemnt.style.padding;
$(elemnt).outerWidth() = elemnt.offsetWidth = elemnt.style.width+elemnt.style.padding+elemnt.style.border;
$(elemnt).outerWidth(true) = elemnt.style.width+elemnt.style.padding+elemnt.style.border+elemnt.style.margin;
注意
要使用原生的style.xxx方法获取属性,这个元素必须已经有内嵌的样式,如<div style="...."></div>
;
如果原先是通过外部或内部样式表定义css样式,必须使用elemnt.currentStyle[attr] || getComputedStyle(elemnt)[attr]
来获取样式值。
function getStyle(ele,attr){
return ele.currentStyle?
ele.currentStyle[attr]:getComputedStyle(ele)[attr]
}
- 获取元素的位置信息
//jQuery方法
$(elemnt).offset().top //单纯的元素距离文档顶的距离 (包括自身的margin、top、及其他元素的所有距离属性如border,padding等值)
$(elemnt).offset().left //单纯的元素距离文档左边缘的距离。
//返回元素相对于第一个以定位的父元素的偏移距离,注意与上面偏移距的区别;
//原生方法
element.offsetTop();//其实是距离定位父元素的相对距离(包含自身的margin、top距离)
//jQuery方法
$(elemnt).position().left = elemnt.style.left;//单纯的定位偏移left,不包含margin
$(elemnt).position().top = elemnt.style.top;