海水正藍

          面朝大海,春暖花開
          posts - 145, comments - 29, trackbacks - 0, articles - 1
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          再談javascript圖片預(yù)加載技術(shù)

          比onload更快獲取圖片尺寸

          文章更新:2011-05-31
          lightbox類效果為了讓圖片居中顯示而使用預(yù)加載,需要等待完全加載完畢才能顯示,體驗不佳(如filick相冊的全屏效果)。javascript無法獲取img文件頭數(shù)據(jù),真的是這樣嗎?本文通過一個巧妙的方法讓javascript獲取它。

          這是大部分人使用預(yù)加載獲取圖片大小的例子:

          01var 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應(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ù)測試后的最佳處理方式:

          01// 更新:
          02// 05.27: 1、保證回調(diào)執(zhí)行順序:error > ready > load;2、回調(diào)函數(shù)this指向img本身
          03// 04-02: 1、增加圖片完全加載后的回調(diào) 2、提高性能
          04 
          05/**
          06 * 圖片頭數(shù)據(jù)加載就緒事件 - 更快獲取圖片尺寸
          07 * @version 2011.05.27
          08 * @author  TangBin
          10 * @param   {String}    圖片路徑
          11 * @param   {Function}  尺寸就緒
          12 * @param   {Function}  加載完畢 (可選)
          13 * @param   {Function}  加載錯誤 (可選)
          14 * @example imgReady('
          15        alert('size ready: width=' + this.width + '; height=' + this.height);
          16    });
          17 */
          18var imgReady = (function () {
          19    var list = [], intervalId = null,
          20 
          21    // 用來執(zhí)行隊列
          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        // 如果圖片被緩存,則直接返回緩存數(shù)據(jù)
          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                // 如果圖片已經(jīng)在其他地方加載可使用面積檢測
          65                newWidth * newHeight > 1024
          66            ) {
          67                ready.call(img);
          68                onready.end = true;
          69            };
          70        };
          71        onready();
          72         
          73        // 完全加載完畢的事件
          74        img.onload = function () {
          75            // onload在定時器時間差范圍內(nèi)可能比onready快
          76            // 這里進行檢查并保證onready優(yōu)先執(zhí)行
          77            !onready.end && onready();
          78         
          79            load && load.call(img);
          80             
          81            // IE gif動畫會循環(huán)執(zhí)行onload,置空onload即可
          82            img = img.onload = img.onerror = null;
          83        };
          84 
          85        // 加入隊列中定期執(zhí)行
          86        if (!onready.end) {
          87            list.push(onready);
          88            // 無論何時只允許出現(xiàn)一個定時器,減少瀏覽器性能損耗
          89            if (intervalId === null) intervalId = setInterval(tick, 40);
          90        };
          91    };
          92})();

          調(diào)用例子:

          1imgReady(', function () {
          2    alert('size ready: width=' + this.width + '; height=' + this.height);
          3});

          是不是很簡單?這樣的方式獲取攝影級別照片尺寸的速度往往是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)解決方案

          這篇文章發(fā)表于10/03/2011 (星期四)在下午 2:33,所屬分類為javascript。 您可以通過RSS 2.0跟蹤這篇文章的評論。 您可以發(fā)表回復(fù),或從您的網(wǎng)站發(fā)布引用通告

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
          博客園   IT新聞   Chat2DB   C++博客   博問  
           
          主站蜘蛛池模板: 大厂| 德阳市| 乌拉特中旗| 深圳市| 德保县| 东至县| 晴隆县| 容城县| 玉门市| 义乌市| 高邮市| 阜阳市| 乐昌市| 会昌县| 方城县| 天全县| 郧西县| 伊川县| 云梦县| 交口县| 大关县| 云和县| 穆棱市| 阜城县| 庆城县| 株洲县| 昌江| 桂阳县| 山阳县| 石台县| 扎囊县| 肇庆市| 府谷县| 迁安市| 沂南县| 禄丰县| 龙陵县| 红河县| 康马县| 昌江| 思茅市|