在圖片的加載策略以前,咱們先來了解下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張可見區域外的圖片,以免出現這個問題。