摘要:本小節將討論與圖片加載時機相關的技術預加載與懶加載。同樣,可將請求成功與失敗的回調,作為圖片預加載成功與失敗的處理。
目前,出于性能與靈活性方面的考慮,我們都將一些小圖片替換成矢量圖或者字體。除了這些能被替換的小圖之外,還有一些不得不使用位圖的場景,如照片、背景等。對于這些位圖,我們需要考慮它們在加載過程中的不同狀態,而制定不同的表現方案。
圖片加載過程中的狀態,大致包括:
何時決定加載圖片
加載中
加載結束,失敗的處理
本文將對比加載過程中的各個狀態表現的不同實現方案,并對方案的簡易程度、兼容性、可擴展性進行分析。
決定加載圖片的時機一般情況,頁面加載時圖片資源作為多帶帶的請求向服務器獲取。有時,由于圖片的數量與大小的影響,這導致頁面加載緩慢,而且加載了許多用戶未觸發的圖片,也白白浪費了流量;有時,又需要保證用戶瀏覽網頁的流暢性,不得不預先加載好圖片,等用戶觸發顯示圖片。
可見,正確的圖片加載時機對提高用戶體驗有很大的幫助。本小節將討論與圖片加載時機相關的技術:預加載與懶加載。
預加載預加載技術就是在用戶觸發圖片顯示之前,先將圖片加載到本地。當用戶觸發圖片顯示的事件時,瀏覽器能夠及時渲染出圖片,保證了用戶瀏覽網頁的流暢性。那么,如何實現預加載呢?本文將介紹三種實現預加載的技術。
該方法只需將欲加載的圖片url寫入某個隱藏元素的background屬性中,讓這張圖片和CSS文件同時加載。當用戶觸發顯示圖片的事件時,再將圖片插入到目標位置。
如下代碼所示,這里用到CSS3的background多圖片特性,只需一個隱藏元素即可預加載所有圖片。
.nothing-1 { display: none; background: url("1.jpg"), url("2.jpg"), url("3.jpg"); }
(關于background多圖片特性的兼容性:http://caniuse.com/#search=cs... )
該方法的缺點在于無法控制預加載的時機,只能是頁面加載時一起加載圖片,如果圖片過多,會阻塞頁面的load事件,延長頁面加載時間。
第二種實現預加載的技術,是直接使用JavaScript新建Image對象,對其src屬性賦值。
如下代碼所示:
var image = new Image(); image.src = "...img url"; image.onload = function() { ... } image.onerror = function () { ... }
還可以利用Image對象的load事件和error事件,完成圖片預加載和失敗之后的處理,如所有圖片加載完成后的提示等。
最后這種方法則是直接發送ajax請求,獲取圖片資源。同樣,可將ajax請求成功與失敗的回調,作為圖片預加載成功與失敗的處理。
如下代碼所示(僅針對webkit瀏覽器):
var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) { ... } } } xhr.open("GET", "...img url"); xhr.send("");
Ajax請求方法無需多余的Image對象,而且獲取的資源也不僅局限于圖片。
懶加載懶加載的核心思想是根據用戶需要加載圖片資源,并非在渲染頁面時就獲取所有圖片。如此,不僅可以減輕服務器的壓力節省用戶流量,還可以提高頁面加載速度。
首先,將頁面中所有圖片url寫進img的"data-src"屬性,并將默認的loading圖片寫入src,作為加載中的圖片樣式。
其次,是確定判斷圖片加載的時機,即當圖片進入瀏覽器的可視區域中時。那么問題來了,如何判斷某個元素進入可視區域呢?
以垂直方向為例,判斷元素是否進入可視區,首先我們需要知道:
可視區域的高度:window.innerHeight(IE9以前不可用)|| document.documentElement.clientHeight (IE標準模式);
元素相對于可視區域頂端位置:element.getBoundingClientRect().top;
元素相對于可視區域底端位置:element.getBoundingClientRect().bottom;
判斷是否進入可視區,即判斷元素的頂部相對于可視區域頂端位置是否大于0,且又小于可視區域高度;或者,元素的底部相對于可視區域底端位置是否大于0,且又小于可視區域高度。
上圖中列出了元素進入可視區的所有情形,從上到下來看,第一個元素的top與bottom的值都小于0,不在可視區內;第二個元素的top小于0,而bottom卻在0到clientHeight之間,已在可視區內,需要加載;第三個元素的top與bottom都滿足條件,在可視區中;剩下的兩個元素與頭兩元素情況一致。
等到元素進入可視區域,就將img元素的"data-src"屬性賦值給"src"屬性,并標記該img元素正在加載,不再做此處理。
以上過程偽代碼如下:
function check() { imgs.forEach(function(img, index) { if (loadedList.indexOf(index) >= 0) { return; } if (!isInClient(container)) { return; } loadedList.push(index); loadImage(img); }) }
最后,將判斷圖片進入可視區域后加載的check函數,寫入window的scroll和resize事件即可。
有時用戶若只想查看排序較后的圖片,會快速滾動滾動條,這種情況下快速滾動過的圖片也沒有必要加載了。
該優化的實現思路也很簡單,延遲加載邏輯,計時器一到再判斷元素是否還在可視區域,可將代碼修改為如下:
function check() { imgs.forEach(function(img, index) { if (loadedList.indexOf(index) >= 0) { return; } if (!isInClient(container)) { return; } setTimeout(function() { if (!isInClient(container)) { return; } loadedList.push(index) loadImage(img) }, 1000); }) }加載中狀態
圖片出于加載中的狀態時,需要給用戶“圖片正在加載”的提示,圖片加載完成后,將提示隱藏。下面,本文將給出加載中提示的兩種實現方案。
方案一:利用img元素background此方案的實現思路是:將“加載中”提示作為img的背景,當圖片正在加載中時,頁面顯示的是背景;圖片加載完成,則覆蓋了背景顯示出圖片。
關鍵代碼:
.img { width: 500px; height: 300px; background: url("data:image/gif;base64,...") center no-repeat; }
這里將“加載中”的動態圖片作為img標簽的background,并且轉換base64編碼,這樣可以減少一次請求。
瀏覽器兼容情況見下表:
瀏覽器 | Chrome 54 | Safari 10.0 | Firefox 50.0 | IE 8 |
---|---|---|---|---|
兼容性 | √ | √ | √ | √ |
兼容性沒有問題,唯一的限制是需要設定.img的寬高。若事先無法得到圖片的寬高,則可以在img標簽外套一層 img元素的load事件會在圖片加載完成后觸發,所以我們可以利用這一特點,進行加載中提示。 關鍵代碼如下: 這種方法需要js配合,無論是加載中的提示動畫還是圖片都可以原始尺寸展示,而不需要再設置。 兼容性也毫無問題: 上面介紹的兩種方案都能實現“加載中”提示,方案一只需要CSS即可,方案二需要js配合但靈活性更強。 加載中的動畫不僅可以用圖片,還可以用CSS3的動畫特性,對于以上兩種方案稍作修改也可以適配CSS3的加載中動畫提示: 方案一:加載動畫作為外層div的內容,但z-index比圖片低,等圖片加載完即可覆蓋; 方案二:用js控制img和加載中動畫的顯示與隱藏即可,圖片加載完隱藏加載中動畫,顯示圖片,并可設置過渡動畫增強體驗; 圖片加載結束具有兩種結果,要么加載成功,要么失敗。加載成功,我們不需多做處理,而加載失敗會出現難看的裂圖提示,影響體驗。 本文介紹兩種方法,替換圖片加載失敗的裂圖提示。 img是可替換元素,即其表現的形式與內容是被外部資源控制。當img未加載時,屬于它的:before與:after偽元素并未渲染,只有當圖片加載失敗時,這兩個偽元素才會出現。 這里給出加載失敗的樣式例子,CSS關鍵樣式如下: 因為渲染后:before和:after偽元素位于img元素里,故將img元素設為relative,:before作為背景,絕對定位覆蓋默認裂圖提示,:after作為提示文字居中在img元素中。 這種方法實現很方便,而且樣式可控,但是兼容性實在太差,只有Chrome支持,其他瀏覽器都無法在圖片加載失敗后渲染出:before和:after偽元素。 翻了翻規范 https://www.w3.org/TR/CSS22/g... This specification does not fully define the interaction of :before and :after with replaced elements (such as IMG in HTML). This will be defined in more detail in a future specification. 所以,替換元素的:before、:after偽元素由瀏覽器產商自己實現,兼容性如下: 與加載成功事件load相似,加載失敗也會觸發對應的事件——error。我們可以利用error事件,當加載失敗時替換img的src為加載失敗提示圖的url。 關鍵代碼如下: 其中error響應事件中要記得將img的onerror屬性置null,否則一旦加載失敗提示圖也加載失敗時會陷入死循環。 該方案可以支持當前主流瀏覽器: 以上兩種替換圖片加載失敗裂圖提示的方案,第一種因兼容性的關系只能用于特殊情況,第二種方案需要js配合,但無兼容性問題。 http://perishablepress.com/3-... http://www.zhangxinxu.com/wor... http://www.cnblogs.com/a_bu/a... 文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。 轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/50521.html
方案二:利用img元素的load事件
實現思路:首次渲染img元素時,將“加載中”提示作為img元素,真正的圖片則用另一個Image對象加載。等到真正的圖片加載完成,即觸發了Image對象的load事件,則將img元素的src修改為真正圖片的url。Array.from(document.getElementsByTagName("img")).forEach(img => {
const image = new Image();
image.src = img.dataset.src;
image.onload = () => img.src = image.src;
})
瀏覽器
Chrome 54
Safari 10.0
Firefox 50.0
IE 8
兼容性
√
√
√
√
.broken-image {
width: 100%;
position: relative;
min-height: 50px;
}
.broken-image:before {
content: " ";
position: absolute;
top: -10px;
left: 0;
height: calc(100% + 10px);
width: 100%;
background-color: rgb(230, 230, 230);
border: 2px dotted rgb(200, 200, 200);
border-radius: 5px;
}
.broken-image:after {
content: "f127" " Broken Image ";
display: block;
font-size: 16px;
font-style: normal;
font-family: FontAwesome;
color: rgb(100, 100, 100);
position: absolute;
top: 5px;
left: 0;
width: 100%;
text-align: center;
line-height: 2;
}
方案二:利用img元素的error事件
瀏覽器
Chrome 54
Safari 10.0
Firefox 50.0
IE 8
兼容性
√
?
?
?
Array.from(document.getElementsByTagName("img")).forEach(img => {
img.onerror = () => {
img.onerror = null;
img.src = "data:image/gif;base64...";
}
});
瀏覽器
Chrome 54
Safari 10.0
Firefox 50.0
IE 8
兼容性
√
√
√
√
摘要:我知道最近世麟心情是錯綜復雜,但還好的是絕大多數程序員都是特別有善心的。如果圖像數據較大就會造成對象申請的內存較多,如果圖像過多就會造成內存不夠用自然就會出現的現象。第二次將設置為再次調用函數時就能生成了。 目錄介紹 01.先看一個需求分析案例 02.Bitmap占用內存介紹 03.影響Bitmap占用內存因素 04.圖像加載的方式 05.加載圖像內存去哪里了 06.具體實現加載圖片...
閱讀 3011·2021-10-27 14:15
閱讀 2999·2021-09-07 10:18
閱讀 1320·2019-08-30 15:53
閱讀 1570·2019-08-26 18:18
閱讀 3373·2019-08-26 12:15
閱讀 3460·2019-08-26 10:43
閱讀 654·2019-08-23 16:43
閱讀 2207·2019-08-23 15:27