比onload更快獲取圖片尺寸
文章更新:2011-05-31
lightbox類效果為了讓圖片居中顯示而使用預(yù)加載,需要等待完全加載完畢才能顯示,體驗不佳(如filick相冊的全屏效果)。javascript無法獲取img文件頭數(shù)據(jù),真的是這樣嗎?本文通過一個巧妙的方法讓javascript獲取它。
這是大部分人使用預(yù)加載獲取圖片大小的例子:
01 | var imgLoad = function (url, callback) { |
02 | var img = new Image(); |
06 | callback(img.width, img.height); |
08 | img.onload = function () { |
09 | callback(img.width, img.height); |
可以看到上面必須等待圖片加載完畢才能獲取尺寸,其速度不敢恭維,我們需要改進。
web應(yīng)用程序區(qū)別于桌面應(yīng)用程序,響應(yīng)速度才是最好的用戶體驗。如果想要速度與優(yōu)雅兼得,那就必須提前獲得圖片尺寸,如何在圖片沒有加載完畢就能獲取圖片尺寸?
十多年的上網(wǎng)經(jīng)驗告訴我:瀏覽器在加載圖片的時候你會看到圖片會先占用一塊地然后才慢慢加載完畢,并且不需要預(yù)設(shè)width與height屬性,因 為瀏覽器能夠獲取圖片的頭部數(shù)據(jù)。基于此,只需要使用javascript定時偵測圖片的尺寸狀態(tài)便可得知圖片尺寸就緒的狀態(tài)。
當(dāng)然實際中會有一些兼容陷阱,如width與height檢測各個瀏覽器的不一致,還有webkit new Image()建立的圖片會受以處在加載進程中同url圖片影響,經(jīng)過反復(fù)測試后的最佳處理方式:
02 | // 05.27: 1、保證回調(diào)執(zhí)行順序:error > ready > load;2、回調(diào)函數(shù)this指向img本身 |
03 | // 04-02: 1、增加圖片完全加載后的回調(diào) 2、提高性能 |
06 | * 圖片頭數(shù)據(jù)加載就緒事件 - 更快獲取圖片尺寸 |
10 | * @param {String} 圖片路徑 |
11 | * @param {Function} 尺寸就緒 |
12 | * @param {Function} 加載完畢 (可選) |
13 | * @param {Function} 加載錯誤 (可選) |
15 | alert('size ready: width=' + this.width + '; height=' + this.height); |
18 | var imgReady = ( function () { |
19 | var list = [], intervalId = null , |
24 | for (; i < list.length; i++) { |
25 | list[i].end ? list.splice(i--, 1) : list[i](); |
27 | !list.length && stop(); |
32 | clearInterval(intervalId); |
36 | return function (url, ready, load, error) { |
37 | var onready, width, height, newWidth, newHeight, |
42 | // 如果圖片被緩存,則直接返回緩存數(shù)據(jù) |
45 | load && load.call(img); |
53 | img.onerror = function () { |
54 | error && error.call(img); |
56 | img = img.onload = img.onerror = null ; |
60 | onready = function () { |
62 | newHeight = img.height; |
63 | if (newWidth !== width || newHeight !== height || |
64 | // 如果圖片已經(jīng)在其他地方加載可使用面積檢測 |
65 | newWidth * newHeight > 1024 |
74 | img.onload = function () { |
75 | // onload在定時器時間差范圍內(nèi)可能比onready快 |
76 | // 這里進行檢查并保證onready優(yōu)先執(zhí)行 |
77 | !onready.end && onready(); |
79 | load && load.call(img); |
81 | // IE gif動畫會循環(huán)執(zhí)行onload,置空onload即可 |
82 | img = img.onload = img.onerror = null ; |
88 | // 無論何時只允許出現(xiàn)一個定時器,減少瀏覽器性能損耗 |
89 | if (intervalId === null ) intervalId = setInterval(tick, 40); |
調(diào)用例子:
2 | alert( 'size ready: width=' + this .width + '; height=' + this .height); |
是不是很簡單?這樣的方式獲取攝影級別照片尺寸的速度往往是onload方式的幾十多倍,而對于web普通(800×600內(nèi))瀏覽級別的圖片能達到秒殺效果。看了這個再回憶一下你見過的web相冊,是否絕大部分都可以重構(gòu)一下呢?好了,請觀賞令人愉悅的 DEMO :
http://www.planeart.cn/demo/imgReady/
(通過測試的瀏覽器:Chrome、Firefox、Safari、Opera、IE6、IE7、IE8)
planeArt.cn原創(chuàng)文章,原文地址:http://www.planeart.cn/?p=1121
其他文章:
1、再談IE6之Fixed定位
2、簡易的全屏透明遮罩(lightBox)解決方案