再談javascript圖片預先載入技術

來源:互聯網
上載者:User
比onload更快擷取圖片尺寸

文章更新:2011-05-31
lightbox類效果為了讓圖片置中顯示而使用預先載入,需要等待完全載入完畢才能顯示,體驗不佳(如filick相簿的全屏效果)。javascript無法擷取img檔案頭資料,真的是這樣嗎?本文通過一個巧妙的方法讓javascript擷取它。

這是大部分人使用預先載入擷取圖片大小的例子:

 
var imgLoad = function (url, callback) {02    var img = new Image();03 04    img.src = url;05    if (img.complete) {06        callback(img.width, img.height);07    } else {08        img.onload = function () {09            callback(img.width, img.height);10            img.onload = null;11        };12    };13 14};

 

可以看到上面必須等待圖片載入完畢才能擷取尺寸,其速度不敢恭維,我們需要改進。

web應用程式區別於傳統型應用程式,響應速度才是最好的使用者體驗。如果想要速度與優雅兼得,那就必須提前獲得圖片尺寸,如何在圖片沒有載入完畢就能擷取圖片尺寸?

十多年的上網經驗告訴我:瀏覽器在載入圖片的時候你會看到圖片會先佔用一塊地然後才慢慢載入完畢,並且不需要預設width與height屬性,因為瀏覽器能夠擷取圖片的頭部資料。基於此,只需要使用javascript定時偵測圖片的尺寸狀態便可得知圖片尺寸就緒的狀態。

當然實際中會有一些相容陷阱,如width與height檢測各個瀏覽器的不一致,還有webkit new Image()建立的圖片會受以處在載入進程中同url圖片影響,經過反覆測試後的最佳處理方式:

 

    // 更新:02// 05.27: 1、保證回調執行順序:error > ready > load;2、回呼函數this指向img本身03// 04-02: 1、增加圖片完全載入後的回調 2、提高效能04 05/**06 * 圖標題資料載入就緒事件 - 更快擷取圖片尺寸07 * @version 2011.05.2708 * <a href="http://my.oschina.net/arthor" class="referer" target="_blank">@author</a> TangBin09 * <a href="http://my.oschina.net/see" class="referer" target="_blank">@see</a>     http://www.planeart.cn/?p=112110 * @param   {String}    圖片路徑11 * @param   {Function}  尺寸就緒12 * @param   {Function}  載入完畢 (可選)13 * @param   {Function}  載入錯誤 (可選)14 * @example imgReady('http://www.google.com.hk/intl/zh-CN/images/logo_cn.png', function () {15        alert('size ready: width=' + this.width + '; height=' + this.height);16    });17 */18var imgReady = (function () {19    var list = [], intervalId = null,20 21    // 用來執行隊列22    tick = function () {23        var i = 0;24        for (; i < list.length; i++) {25            list[i].end ? list.splice(i--, 1) : list[i]();26        };27        !list.length && stop();28    },29 30    // 停止所有定時器隊列31    stop = function () {32        clearInterval(intervalId);33        intervalId = null;34    };35 36    return function (url, ready, load, error) {37        var onready, width, height, newWidth, newHeight,38            img = new Image();39 40        img.src = url;41 42        // 如果圖片被緩衝,則直接返回快取資料43        if (img.complete) {44            ready.call(img);45            load && load.call(img);46            return;47        };48 49        width = img.width;50        height = img.height;51 52        // 載入錯誤後的事件53        img.onerror = function () {54            error && error.call(img);55            onready.end = true;56            img = img.onload = img.onerror = null;57        };58 59        // 圖片尺寸就緒60        onready = function () {61            newWidth = img.width;62            newHeight = img.height;63            if (newWidth !== width || newHeight !== height ||64                // 如果圖片已經在其他地方載入可使用面積檢測65                newWidth * newHeight > 102466            ) {67                ready.call(img);68                onready.end = true;69            };70        };71        onready();72 73        // 完全載入完畢的事件74        img.onload = function () {75            // onload在定時器時間差範圍內可能比onready快76            // 這裡進行檢查並保證onready優先執行77            !onready.end && onready();78 79            load && load.call(img);80 81            // IE gif動畫會迴圈執行onload,置空onload即可82            img = img.onload = img.onerror = null;83        };84 85        // 排入佇列中定期執行86        if (!onready.end) {87            list.push(onready);88            // 無論何時只允許出現一個定時器,減少瀏覽器效能損耗89            if (intervalId === null) intervalId = setInterval(tick, 40);90        };91    };92})();

 

調用例子:

 

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

  

是不是很簡單?這樣的方式擷取攝影層級照片尺寸的速度往往是onload方式的幾十多倍,而對於web普通(800×600內)瀏覽層級的圖片能達到秒殺效果。看了這個再回憶一下你見過的web相簿,是否絕大部分都可以重構一下呢?好了,請觀賞令人愉悅的 DEMO :

http://www.planeart.cn/demo/imgReady/

(通過測試的瀏覽器:Chrome、Firefox、Safari、Opera、IE6、IE7、IE8)

planeArt.cn原創文章,原文地址:http://www.planeart.cn/?p=1121

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.