在图片的加载策略以前,咱们先来了解下html网页中,图片的不一样位置的图片分别是在何时发起图片资源请求的javascript
img标签会在html渲染解析到的时候,若是解析到img src值,则浏览器会当即开启一个线程去请求该资源。 正常状况是解析到了src便发起请求,css
<img src="img1.jpg" style="display: none" />
复制代码
发现除了Opera不请求,其余浏览器都会立刻请求,html
<img src="img1.jpg" style="visible: hidden" />
复制代码
所有浏览器都会请求 2. img 同一张图重复java
<img src="img2.jpg" />
<img src="img2.jpg" />
复制代码
全部的浏览器都只请求一次,由于http在发出请求的时候,会检验是否有缓存,有缓存就会从缓存读取 那么你知道如何判断资源是不是缓存仍是服务器返回的呢,看这边jquery
<style type="text/css">
.test1 { background: url(bg1.jpg) }
.test2 { background: url(bg1.jpg) }
</style>
<div class="test1">test1</div>
<div class="test2">test2</div>
复制代码
全部浏览器都只发起一次请求promise
<style type="text/css">
.test3 { display: none; background: url(bg2.jpg) }
</style>
<div class="test3">test1</div>
复制代码
Opera 和Firefox对display:none的元素的背景,不会当即发生请求,只有当其display 不为none才会发起图片请求。其余浏览器则是当即发起请求浏览器
<style type="text/css">
.test1 { background: url(bg1.jpg) }
.test1 { background: url(bg2.jpg) }
</style>
<div class="test1">test1</div>
复制代码
重写背景,浏览器只会请求覆盖的那个背景图缓存
<style type="text/css">
.test1 { background-image:url("haorooms.jpg"),url("http2.jpg"); }
</style>
<div class="test1">test1</div>
复制代码
对所有的背景都会请求bash
<style type="text/css">
.test3 { background: url(bg3.jpg) }
.test4 { background: url(bg4.jpg) }
</style>
<div class="test3">test1</div>
复制代码
.test4并不存在,这个时候,浏览器并不会去请求bg3.jpg,当且仅当背景的应用元素存在时(无论在当前是显示仍是不显示),才会发生请求服务器
<style type="text/css">
a.test1 { background: url(haorooms.jpg); }
a.test1:hover { background: url(http2.jpg); }
</style>
<div href="#" class="test1">test1</div>
复制代码
触发hover的时候,才会请求hover下的背景。在实际中,会遇到这个背景图初次显示闪一下的状况,若是要优化,就预加载这张图便可。
<script type="text/javascript">
var el = document.createElement('div');
el.innerHTML = '<img src="haorooms.jpg" />';
//document.body.appendChild(el);
</script>
复制代码
只有Opera 不会立刻请求图片,其余浏览器都是执行了代码就发起请求,Opera必定要元素添加到dom时,才会发出请求
在作项目的过程当中,常常会遇到须要图片预加载与懒加载,图片预加载就是为了在展现的时候减小图片加载过程很差的载入体验,而图片懒加载则是处于这张图片不在当前可视区域展现,为了网络带宽以及提高首次加载速度而作的优化。
const preloadImg = (url) => {
const img = new Image();
if(img.complete) {
//图片已经加载过了,可使用图片
//do something here
}
else {
img.onload = function() {
//图片首次加载完成,可使用图片
//do something here
};
}
img.src = url;
}
复制代码
注意,最好是先定义onload,再赋值src,否则会出现资源返回,可是onload尚未挂载的状况。
在实际的项目我遇到过的,就是须要在某些图片加载完成再作下一步,那么这个时候,咱们就须要知道某些图片序列肯定是预加载完成,一样仍是使用preloadImg,结合一下promise,有多个图片资源,能够用promise.all。就能够保证全部的图片加载完成再进行下一步
var promiseAll = imgData.map(function (item, index) {
return new Promise(function (resolve, reject) {
var img = new Image();
img.onload = function () {
img.onload = null;
resolve(img);
};
img.error = function () {
reject('图片加载失败');
};
img.src = item;
});
});
Promise.all(promiseAll).then(
function () {
// 图片所有加载完成,进行下一步
// todo
},
function (err) {
console.log(err);
}
);
复制代码
所谓图片懒加载,就是延迟加载图片资源,是对网页性能的一种优化方式,好比当咱们打开一个网页的时候,优先展现的图片,好比首屏图片,就先加载,而其余的图片,当须要展现的时候,再去请求图片资源,避免了首次打开时,一次性加载过多图片资源。
一样地,咱们再回顾一下文章开始讲的,若是是img标签,浏览器解析到img的src有值,就会去发起请求,那么咱们就能够借助这个操做,在懒加载的图片,先不赋值,等到须要展现的时候,再赋值
<img class="show-img" data-src="//static/show.jpg" />
const src = $('.show-img').attr('data-src');
$('.show-img').attr(src, src);
复制代码
通常实际中,咱们不会在须要展现的时候,才发起图片请求,否则就不会有图片预加载的需求了,那么如何判断图片在什么时候须要展现呢?在下拉流之类的网页中,咱们通常是在图片距离可视区域的必定距离,好比50px,就开始请求图片资源
方法一:
A: document.documentElement.clientHeight 可视窗口的高度
B: element.offsetTop dom相对于文档顶部的距离
C: document.documentElement.scrollTop 滚动条滚动的距离
B - C < A 即说明元素在可视区域内
方法二:getBoundingClientRect
const domObj = element.getBoundingClientRect(); domObj.top:元素上边到视窗上边的距离;
domObj.right:元素右边到视窗左边的距离;
domObj.bottom:元素下边到视窗上边的距离;
domObj.left:元素左边到视窗左边的距离;
const clientHeight = window.innerHeight;
当 domObj.top < clientHeight 表示dom在可视区域内了
const preImages = $('img[data-src]').not('.pred-img');
Array.from(preImages).forEach((item) => {
if (isPreLoad(item)) {
loadImg(item);
}
});
const loadImg = (img) => {
if (!img.src) {
img.src = img.attr('data-src').addClass('pred-img');
}
};
const isPreLoad = () {
const preObj = getBoundingClientRect();
const cH = $(window).height();
return preObj <= cH + 100;
};
复制代码
代码中有二处,一处是not('.pred-img'),做为加载过的图片的标记,第二处是识别区域高度加了100,提早100px的地方就开始加载。固然在具体展现的时候,还能够给图片添加加载中的样式,以及识别图片加载异常
<img class="avater scrollLoading" data-src="../image/show.png" onerror='this.src="../images/avatar.png"'>
复制代码
_ ### jquery.lazyload 插件
<div class="article-content">
<img data-original="img/show1.jpg">
<img data-original="img/show2.jpg">
<img data-original="img/show3.jpg">
<img data-original="img/show4.jpg">
<img data-original="img/show5.jpg">
<img data-original="img/show6.jpg">
</div>
require('./libs/jquery.lazyload');
addImagesLazyload();
function addImagesLazyload() {
var $images = $('.article-content img:not([data-lazyload])');
var preCount = 2;
$images.each(function(i, img) {
var $img = $(img);
var $box = $img.parent();
var src = $img.attr('data-original');
if (src && !src.match(/\?/)) {
src += '?imageView2/2/w/750';
}
$img.attr('data-lazyload', 1);
$img.off('error').on('error', function() {
$box.addClass('img-error');
});
$img.off('load').on('load', function() {
$box.removeClass('img-box img-error');
});
if (src) {
$img.attr('data-original', src);
if (i < preCount) {
img.setAttribute('src', src);
}
}
});
var $lazyed = $images.slice(preCount);
if ($lazyed.length) {
$lazyed.lazyload({ // 使用lazyload
threshold: 200 // 图片距离可视区200px的时候开始请求
});
}
}
复制代码
preCount 是加载页面的时候想要加载的图片,其余的图片就是懒加载。load 与error中就能够添加图片加载与加载失败默认显示图片 关于lazyload的配置参数以下: placeholder : "img/img.jpg" 占位图片,此图片用来占据将要加载的图片的位置,待图片加载时,占位图则会隐藏 effect: "fadeIn" 图片加载效果, 可取值有show(直接显示),fadeIn(淡入),slideDown(下拉) threshold: 200 滚动条在离目标位置还有200的高度时就开始加载图片,能够作到不让用户察觉 event: 'click' 点击事件触发时才加载 值有click(点击),mouseover(鼠标划过),sporty(运动的),foobar(…).能够实现鼠标莫过或点击图片才开始加载 ailurelimit : 10 failurelimit,值为数字.lazyload默认在找到第一张不在可见区域里的图片时则再也不继续加载,但当HTML容器混乱的时候可能出现可见区域内图片并没加载出来的状况,failurelimit意在加载N张可见区域外的图片,以免出现这个问题。