国产成人精品无码青草_亚洲国产美女精品久久久久∴_欧美人与鲁交大毛片免费_国产果冻豆传媒麻婆精东

18143453325 在線咨詢 在線咨詢
18143453325 在線咨詢
所在位置: 首頁 > 營銷資訊 > 網(wǎng)絡(luò)營銷 > 實(shí)現(xiàn)網(wǎng)頁圖片預(yù)加載效果的3種技術(shù)方法

實(shí)現(xiàn)網(wǎng)頁圖片預(yù)加載效果的3種技術(shù)方法

時(shí)間:2022-05-29 08:03:01 | 來源:網(wǎng)絡(luò)營銷

時(shí)間:2022-05-29 08:03:01 來源:網(wǎng)絡(luò)營銷

網(wǎng)站開發(fā)時(shí)經(jīng)常需要在某個(gè)頁面需要實(shí)現(xiàn)對(duì)大量圖片的瀏覽,如果考慮流量的話,大可每個(gè)頁面只顯示一張圖片,讓用戶每看一張圖片就需要重新下載一下整個(gè)頁面。不過,在web2.0時(shí)代,更多人愿意用javascript來實(shí)現(xiàn)一個(gè)圖片瀏覽器,讓用戶無需等待過長的時(shí)間就能看到其他圖片。所以,對(duì)于一個(gè)網(wǎng)站來說,網(wǎng)頁的預(yù)加載就顯得尤為重要。在此,億企邦從網(wǎng)上找了3種預(yù)加載的代碼,就在億企邦上跟大家分享一下,共同分析一下:

一、常規(guī)實(shí)現(xiàn)圖片預(yù)加載的方法

知道了一張圖片的地址,需要把它在一個(gè)固定大小的html容器(可以是div等)里邊顯示出來,最重要的當(dāng)然是需要知道這張即將顯示的圖片的寬和高,然后再結(jié)合容器的寬和高,按照一定的縮放比例使圖片顯示出來。因此,實(shí)現(xiàn)圖片預(yù)加載就成為圖片瀏覽器的核心功能了。

做過圖片翻轉(zhuǎn)效果的朋友其實(shí)都知道,要讓圖片輪換的時(shí)候不出現(xiàn)等待,最好是先讓圖片下載到本地,讓瀏覽器緩存起來。這時(shí),一般都會(huì)用到j(luò)s里邊的Image對(duì)象。一般的手段無非這樣:

function preLoadImg(url) {
  var img = new Image();
  img.src = url;
  }

通過調(diào)用preLoadImg函數(shù),傳入圖片的url,就能使圖片預(yù)先下載下來了。實(shí)際上,億企邦覺得這里用到的預(yù)下載功能也和這基本一致。圖片預(yù)下載下來后,通過img的width和height屬性,就能知道圖片的寬和高了。

但是需要考慮到,在做圖片瀏覽器功能時(shí),圖片都是實(shí)時(shí)顯示的。比如你點(diǎn)了顯示的按鈕,這個(gè)時(shí)候才會(huì)調(diào)用上邊類似的代碼來加載圖片。因此,如果你直接用img.width的時(shí)候,圖片還沒有完全下載下來。因此,需要用一些異步的方法,等到圖片下載完畢的時(shí)候才會(huì)再對(duì)img的width和height進(jìn)行調(diào)用。

實(shí)現(xiàn)這樣的異步方法實(shí)際上不難,圖片的下載完畢事件也很簡單,就是簡單的onload事件。因此,我們可以利用下面的代碼:

function loadImage(url, callback) {
   var img = new Image();
   img.src = url;
   img.onload = function(){ //圖片下載完畢時(shí)異步調(diào)用callback函數(shù)。
   callback.call(img); // 將callback函數(shù)this指針切換為img。
   };
  }

好了,再來寫一個(gè)測試用例:

function imgLoaded(){
   alert(this.width);
  }
  <input type="button" value="loadImage" onclick="loadImage('aaa.jpg',imgLoaded)"/>

在firefox中測試一下,發(fā)現(xiàn)不錯(cuò),果然和預(yù)想的效果一樣,在圖片下載后,就會(huì)彈出圖片的寬度來。無論點(diǎn)擊多少次或者刷新結(jié)果都一樣。

不過,做到這一步,先別高興太早——還需要考慮一下瀏覽器的兼容性,于是,趕緊到ie里邊測試一下。沒錯(cuò),同樣彈出了圖片的寬度。但是,再點(diǎn)擊load的時(shí)候,情況就不一樣了,什么反應(yīng)都沒有了。刷新一下,也同樣如此。

經(jīng)過對(duì)多個(gè)瀏覽器版本的測試,發(fā)現(xiàn)ie6、opera都會(huì)這樣,而firefox和safari則表現(xiàn)正常。其實(shí),原因也挺簡單的,就是因?yàn)闉g覽器的緩存了。當(dāng)圖片加載過一次以后,如果再有對(duì)該圖片的請(qǐng)求時(shí),由于瀏覽器已經(jīng)緩存住這張圖片了,不會(huì)再發(fā)起一次新的請(qǐng)求,而是直接從緩存中加載過來。

對(duì)于firefox和safari,它們視圖使這兩種加載方式對(duì)用戶透明,同樣會(huì)引起圖片的onload事件,而ie和opera則忽略了這種同一性,不會(huì)引起圖片的onload事件,因此上邊的代碼在它們里邊不能得以實(shí)現(xiàn)效果。

怎么辦呢?最好的情況是Image可以有一個(gè)狀態(tài)值表明它是否已經(jīng)載入成功了。從緩存加載的時(shí)候,因?yàn)椴恍枰却?,這個(gè)狀態(tài)值就直接是表明已經(jīng)下載了,而從http請(qǐng)求加載時(shí),因?yàn)樾枰却螺d,這個(gè)值顯示為未完成。這樣的話,就可以搞定了。

經(jīng)過一些分析,億企邦終于發(fā)現(xiàn)一個(gè)為各個(gè)瀏覽器所兼容的Image的屬性——complete。所以,在圖片onload事件之前先對(duì)這個(gè)值做一下判斷即可。最后,代碼變成如下的樣子:

function loadImage(url, callback) {
   var img = new Image(); //創(chuàng)建一個(gè)Image對(duì)象,實(shí)現(xiàn)圖片的預(yù)下載
   img.src = url;
   if (img.complete) { // 如果圖片已經(jīng)存在于瀏覽器緩存,直接調(diào)用回調(diào)函數(shù)
   callback.call(img);
   return; // 直接返回,不用再處理onload事件
   }
   img.onload = function () { //圖片下載完畢時(shí)異步調(diào)用callback函數(shù)。
   callback.call(img);//將回調(diào)函數(shù)的this替換為Image對(duì)象
   };
  };

經(jīng)過這么一番折騰,總算是讓各個(gè)瀏覽器都能滿足我們的目標(biāo)了。雖然代碼很簡單,但是卻把圖片瀏覽器中最核心的問題解決掉了,接下來你所要做的,僅僅是圖片如何呈現(xiàn)的問題了,當(dāng)然,也可以通過css來實(shí)現(xiàn)圖片的展示效果,具體可查看億企邦的《CSS無圖片技術(shù)的實(shí)現(xiàn)方法有哪些》,在此,我就不多說了。

二、動(dòng)態(tài)圖片的預(yù)加載技術(shù)

一般來說,技術(shù)人員在實(shí)現(xiàn)圖片預(yù)加載的大體思路都是這樣的:

function loadImage(url, callback) {
   var img = new Image(); //創(chuàng)建一個(gè)Image對(duì)象,實(shí)現(xiàn)圖片的預(yù)下載
   img.src = url;
   if (img.complete) { // 如果圖片已經(jīng)存在于瀏覽器緩存,直接調(diào)用回調(diào)函數(shù)
   callback(img);
   return; // 直接返回,不用再處理onload事件
   }
  img.onload = function () { //圖片下載完畢時(shí)異步調(diào)用callback函數(shù)。
   callback(img);
   };
  };

億企邦覺得這個(gè)方法功能是ok的,但是有一些隱患,具體如下:

1、創(chuàng)建了一個(gè)臨時(shí)匿名函數(shù)來作為圖片的onload事件處理函數(shù),形成了閉包。

相信大家都看到過ie下的內(nèi)存泄漏模式的文章,其中有一個(gè)模式就是循環(huán)引用,而閉包就有保存外部運(yùn)行環(huán)境的能力(依賴于作用域鏈的實(shí)現(xiàn)),所以img.onload這個(gè)函數(shù)內(nèi)部又保存了對(duì)img的引用,這樣就形成了循環(huán)引用,導(dǎo)致內(nèi)存泄漏。(這種模式的內(nèi)存泄漏只存在低版本的ie6中,打過補(bǔ)丁的ie6以及高版本的ie都解決了循環(huán)引用導(dǎo)致的內(nèi)存泄漏問題)。

2、只考慮了靜態(tài)圖片的加載,忽略了gif等動(dòng)態(tài)圖片,這些動(dòng)態(tài)圖片可能會(huì)多次觸發(fā)onload。

要解決上面兩個(gè)問題很簡單,其實(shí)很簡單,代碼如下:

img.onload = function () { //圖片下載完畢時(shí)異步調(diào)用callback函數(shù)。
   img.onload = null;
   callback(img);
  };

這樣既能解決內(nèi)存泄漏的問題,又能避免動(dòng)態(tài)圖片的事件多次觸發(fā)問題。

在一些相關(guān)博文中,也有人注意到了要把img.onload 設(shè)置為null,只不過時(shí)機(jī)不對(duì),大部分文章都是在callback運(yùn)行以后,才將img.onload設(shè)置為null,這樣雖然能解決循環(huán)引用的問題,但是對(duì)于動(dòng)態(tài)圖片來說,如果callback運(yùn)行比較耗時(shí)的話,還是有多次觸發(fā)的隱患的。

隱患經(jīng)過上面的修改后,就消除了,但是這個(gè)代碼還有優(yōu)化的余地:

if (img.complete) { // 如果圖片已經(jīng)存在于瀏覽器緩存,直接調(diào)用回調(diào)函數(shù)
   callback(img);
   return; // 直接返回,不用再處理onload事件
  }

關(guān)于這段代碼,億企邦覺得其原因如下:

經(jīng)過對(duì)多個(gè)瀏覽器版本的測試,發(fā)現(xiàn)ie、opera下,當(dāng)圖片加載過一次以后,如果再有對(duì)該圖片的請(qǐng)求時(shí),由于瀏覽器已經(jīng)緩存住這張圖片了,不會(huì)再發(fā)起一次新的請(qǐng)求,而是直接從緩存中加載過來。對(duì)于 firefox和safari,它們?cè)噲D使這兩種加載方式對(duì)用戶透明,同樣會(huì)引起圖片的onload事件,而ie和opera則忽略了這種同一性,不會(huì)引起圖片的onload事件,因此上邊的代碼在它們里邊不能得以實(shí)現(xiàn)效果。

確實(shí),在ie,opera下,對(duì)于緩存圖片的初始狀態(tài),與firefox和safari,chrome下是不一樣的(有興趣的話,可以在不同瀏覽器下,測試一下在給img的src賦值緩存圖片的url之前,img的狀態(tài)),但是對(duì)onload事件的觸發(fā),卻是一致的,不管是什么瀏覽器。產(chǎn)生這個(gè)問題的根本原因在于,img的src賦值與 onload事件的綁定,順序不對(duì)(在ie和opera下,先賦值src,再賦值onload,因?yàn)槭蔷彺鎴D片,就錯(cuò)過了onload事件的觸發(fā))。應(yīng)該先綁定onload事件,然后再給src賦值,代碼如下:

function loadImage(url, callback) {
   var img = new Image(); //創(chuàng)建一個(gè)Image對(duì)象,實(shí)現(xiàn)圖片的預(yù)下載
   img.onload = function(){
   img.onload = null;
   callback(img);
   }
   img.src = url;
  }

這樣內(nèi)存泄漏,動(dòng)態(tài)圖片的加載問題都得到了解決(關(guān)于圖片的優(yōu)化分類可查看億企邦的《網(wǎng)站圖片優(yōu)化的分類有哪些》相關(guān)介紹),而且也以統(tǒng)一的方式,實(shí)現(xiàn)了callback的調(diào)用。

三、比onload更快獲取圖片尺寸的預(yù)加載技術(shù)

大部分技術(shù)人員使用預(yù)加載獲取圖片大小的方法,基本都是通過如下的代碼實(shí)現(xiàn)的:

var imgLoad = function (url, callback) {
   var img = new Image();
   img.src = url;
   if (img.complete) {
   callback(img.width, img.height);
   } else {
   img.onload = function () {
   callback(img.width, img.height);
   img.onload = null;
   };
   };
  };

從以上代碼,我們可以看到上面必須等待圖片加載完畢才能獲取尺寸,其速度億企邦還真不敢恭維,對(duì)此,我們需要改進(jìn)。

web應(yīng)用程序區(qū)別于桌面應(yīng)用程序,響應(yīng)速度才是最好的用戶體驗(yàn)。如果想要速度與優(yōu)雅兼得,那就必須提前獲得圖片尺寸,如何在圖片沒有加載完畢就能獲取圖片尺寸呢?

據(jù)億企邦十多年的上網(wǎng)經(jīng)驗(yàn):瀏覽器在加載圖片的時(shí)候你會(huì)看到圖片會(huì)先占用一塊地然后才慢慢加載完畢,并且不需要預(yù)設(shè)width與height屬性,因?yàn)闉g覽器能夠獲取圖片的頭部數(shù)據(jù)?;诖耍恍枰褂胘avascript定時(shí)偵測圖片的尺寸狀態(tài)便可得知圖片尺寸就緒的狀態(tài)。

當(dāng)然實(shí)際中會(huì)有一些兼容陷阱,如width與height檢測各個(gè)瀏覽器的不一致,還有webkit new Image()建立的圖片會(huì)受以處在加載進(jìn)程中同url圖片影響,經(jīng)過反復(fù)測試后的最佳處理方式:

// 更新:
  // 05.27: 1、保證回調(diào)執(zhí)行順序:error > ready > load;2、回調(diào)函數(shù)this指向img本身
  // 04-02: 1、增加圖片完全加載后的回調(diào) 2、提高性能
  /**
  * 圖片頭數(shù)據(jù)加載就緒事件 - 更快獲取圖片尺寸
  * @version 2011.05.27
  * @author TangBin
  * @seehttp://www.mahaixiang.cn/wyzz/546.html
  * @param {String} 圖片路徑
  * @param {Function} 尺寸就緒
  * @param {Function} 加載完畢 (可選)
  * @param {Function} 加載錯(cuò)誤 (可選)
  * @example imgReady('http://www.mahaixiang.cn/uploads/allimg/1405/1-14050212013ML.jpg', function () {
   alert('size ready: width=' + this.width + '; height=' + this.height);
   });
  */
var imgReady = (function () {
var list = [], intervalId = null,
// 用來執(zhí)行隊(duì)列
tick = function () {
var i = 0;
for (; i < list.length; i++) {
list[i].end ? list.splice(i--, 1) : list[i]();
};
!list.length && stop();
},
// 停止所有定時(shí)器隊(duì)列
stop = function () {
clearInterval(intervalId);
intervalId = null;
};
return function (url, ready, load, error) {
var onready, width, height, newWidth, newHeight,
img = new Image();
img.src = url;
// 如果圖片被緩存,則直接返回緩存數(shù)據(jù)
if (img.complete) {
ready.call(img);
load && load.call(img);
return;
};
width = img.width;
height = img.height;
// 加載錯(cuò)誤后的事件
img.onerror = function () {
error && error.call(img);
onready.end = true;
img = img.onload = img.onerror = null;
};
// 圖片尺寸就緒
onready = function () {
newWidth = img.width;
newHeight = img.height;
if (newWidth !== width || newHeight !== height ||
// 如果圖片已經(jīng)在其他地方加載可使用面積檢測
newWidth * newHeight > 1024
) {
ready.call(img);
onready.end = true;
};
};
onready();
// 完全加載完畢的事件
img.onload = function () {
// onload在定時(shí)器時(shí)間差范圍內(nèi)可能比onready快
// 這里進(jìn)行檢查并保證onready優(yōu)先執(zhí)行
!onready.end && onready();
load && load.call(img);
// IE gif動(dòng)畫會(huì)循環(huán)執(zhí)行onload,置空onload即可
img = img.onload = img.onerror = null;
};
// 加入隊(duì)列中定期執(zhí)行
if (!onready.end) {
list.push(onready);
// 無論何時(shí)只允許出現(xiàn)一個(gè)定時(shí)器,減少瀏覽器性能損耗
if (intervalId === null) intervalId = setInterval(tick, 40);
};
};
})();

調(diào)用例子:

imgReady('http://www.google.com.hk/intl/zh-CN/images/logo_cn.png', function () {
   alert('size ready: width=' + this.width + '; height=' + this.height);
  });

是不是很簡單?這樣的方式獲取攝影級(jí)別照片尺寸的速度往往是onload方式的幾十多倍,而對(duì)于web普通(800×600內(nèi))瀏覽級(jí)別的圖片能達(dá)到秒殺效果。看了這個(gè)再回憶一下你見過的web相冊(cè),是否絕大部分都可以重構(gòu)一下的。

億企邦點(diǎn)評(píng):

預(yù)加載圖片是一個(gè)很好提升用戶體驗(yàn)的小激情,以及讓自己的網(wǎng)站看起來更專業(yè)的一個(gè)途徑,進(jìn)度條可以讓用戶知道加載的進(jìn)展,避免用戶的冷落感,這也能顯著提升你的網(wǎng)站形象。

關(guān)鍵詞:效果,技術(shù),方法

74
73
25
news

版權(quán)所有? 億企邦 1997-2022 保留一切法律許可權(quán)利。

為了最佳展示效果,本站不支持IE9及以下版本的瀏覽器,建議您使用谷歌Chrome瀏覽器。 點(diǎn)擊下載Chrome瀏覽器
關(guān)閉