打造自己的jQuery Plugin+圖片等比例縮小

打造自己的jQuery Plugin+圖片等比例縮小

最近的專案客戶要求一個功能。

例如一個200 * 100 的方框中,要擺入一張圖片,來源圖片的尺寸比例

都不一致,但都要塞入這個框框而且不能變形,所以需要等比例的顯示縮圖。

 

今天把我研究來的心得寫出來,順便研究了一下自訂的jQuery Plugin怎麼做。

如果有看過黑大的邊做邊學jQuery系列,應該對自訂jQuery Plugin不陌生。

裡面有影片又有教學,認真地看一次加上實作,馬上就能學會製作簡單的plugin

參考連結在這:邊做邊學 jQuery 系列 13- 打造自己的jQuery Plugin

 

基本上只要把下面這個框架Copy起來,裡面再加上自己想實作的code

(function($) {
    $.fn.extend({
        method1: function(options) {
            //...code...    
        },
        method2: function(options) {
            //...code...
        }
     });
})(jQuery);

其實還滿簡單的。

 

那開始寫我的等比例縮圖的程式

其實想起來不難,當 圖片的寬 超過我要的框框寬度時,

將寬設為框框寬度,將高設為   框框寬度*  ( 圖片高度 /圖片寬度 )

當圖片高度高過框框高度時

將高設為框框高度,並將寬度設為 框框高度  *  ( 圖片寬度 /圖片高度 )

舉個例:今天我的框框最大寬高是 200 * 100,載入的圖片是 600 * 300

寬 600 > 200 => 寬設為 200,高設為 200 * (  300/ 600 ) = 100

高 300 > 100 => 高設為 100,寬設為 100 * (  600/ 300 ) = 200

只是些簡單的數學,但經我嘗試之後,麻煩的是在

因為當圖片尚未載入完成時,讀取圖片的高度容易發生錯誤。

例如當一張圖片只讀取一半時就去執行改變寬高的動作,寬度因為只要出現一點點

就可以讀到完整的寬度,但高度卻只讀到一半的高度,導致運算結果會有誤。

 

所以要在圖片完全載入之後,才能去改變圖片大小。但是IE跟Firefox對圖片完成載入

的事件支援又不一樣,光這個問題就讓我傷腦筋好久。先試寫了一版算是比較不會

有問題的Plugin來用用看。

先看function的部分

//當瀏覽器為IE時,當圖片readyState狀態為complete時才執行動作
function IEBrower(event) {
    if (this.readyState == "complete") {
        ChangeImg(this, event);
    }
}
//當瀏覽器為Firefox時,當圖片complete狀態為true時才執行動作
function FFBrower(event) {
    if (this.complete == true) {
       ChangeImg(this,event);
    }
}

function ChangeImg(e,event) {
    var HeightWidth = e.offsetHeight / e.offsetWidth; //設置高寬比
    var WidthHeight = e.offsetWidth / e.offsetHeight; //設置寬高比
    //如同上方說明的邏輯
    if (e.offsetWidth > event.data.MaxWidth) {
        e.width = event.data.MaxWidth;
        e.height = event.data.MaxWidth * HeightWidth;
    }
    if (e.offsetHeight > event.data.MaxHeight) {
        e.height = event.data.MaxHeight;
        e.width = event.data.MaxHeight * WidthHeight;
    }
}

再來看Plugin的部分

 

(function ($) {
    //抓瀏覽器的名稱
    var appname = navigator.appName.toLowerCase();

    function changeImgSize(target, options) {
        //處理參數  
        var settings = { MaxWidth: 100, MaxHeight: 100 };
        $.extend(settings, options);
        
        if (appname.indexOf("netscape") == -1) {
            //ie
            $(target).bind("readystatechange"
             , { MaxWidth: settings.MaxWidth, MaxHeight: settings.MaxHeight }
             , IEBrower);
        } else {
        //firefox
            $(target).bind("load"
             , { MaxWidth: settings.MaxWidth, MaxHeight: settings.MaxHeight }
             , FFBrower);
        }
    }

    $.fn.extend({
        reSize: function (options) {
            return this.each(function () {
                changeImgSize(this, options);
            });
        }
    });
})(jQuery);

7、8行我覺得很好用,可先設計這個plugin的預設值,當使用這個plugin時,

如果未傳入參數,則使用預設值,若有傳入則會將傳入的參數蓋過預設值。

因此我框框預設值是100*100。如果我只傳入寬度MaxWidth=200,那框框的最大

寬高就變成200*100。

10~20行是判斷哪種瀏覽器,如果是ie就在圖片上綁readystatechange事件

如果是firefox則綁load事件。

23~29行就是擴充jQuery的方法,方法名叫reSize,並用可以串接的方式去寫。

整個plugin的邏輯是,將傳進來的img去執行changeImgSize(),判斷瀏覽器並

綁上事件,當圖片載入狀態完成時,去執行ChangeImg() 等比例縮圖。

 

寫完之後,只要將js檔載入,就可以在頁面上使用自訂的plugin了。

<script type="text/javascript">
        $(function () {
            $("img").reSize({ MaxWidth: 200, MaxHeight: 200 });
        });
</script>

頁面放八張圖,尺寸及長寬都不一

<table style="border: 1px solid green; background-color: #313131;" class="MyPlugin">
        <tr>
            <td>
                <img id="img1" src="/images/1.jpg" />
            </td>
            <td>
                <img id="img2" src="/images/2.jpg" />
            </td>
            <td>
                <img id="img3" src="/images/3.jpg" />
            </td>
            <td>
                <img id="img4" src="/images/4.jpg" />
            </td>
        </tr>
        <tr>
            <td>
                <img id="img5" src="/images/5.jpg" />
            </td>
            <td>
                <img id="img6" src="/images/6.jpg" />
            </td>
            <td>
                <img id="img7" src="/images/7.jpg" />
            </td>
            <td>
                <img id="img8" src="/images/8.jpg" />
            </td>
        </tr>
    </table>

結果

image

可以看到圖片都很安分的擺在框框裡面。更改成長方形的框並改一下版面配置

image

依舊有用,並且IE跟FireFox都可用。

 

備註:

不過不是每次reload時都會正確縮放,我猜想應該是事件綁的時間太晚了吧。

我將原本沒有寫成plugin的code寫上

<script type="text/javascript">
      var appname = navigator.appName.toLowerCase();

        function Wa_SetImgAutoSize(e) {
            var img = e; //獲取圖片
            var MaxWidth = 190; //設置圖片寬度界限
            var MaxHeight = 190; //設置圖片高度界限
            var HeightWidth = img.offsetHeight / img.offsetWidth; //設置高寬比
            var WidthHeight = img.offsetWidth / img.offsetHeight; //設置寬高比

            if (appname.indexOf("netscape") == -1) {
                //ie
                if (img.readyState != "complete")
                    return false;
            } else {
                //firefox
                if (img.complete != true)
                    return false;
            } 
            if (img.offsetWidth > MaxWidth) {
                img.width = MaxWidth;
                img.height = MaxWidth * HeightWidth;
            }
            if (img.offsetHeight > MaxHeight) {
                img.height = MaxHeight;
                img.width = MaxHeight * WidthHeight;
            }
        }
    </script>
    <table style="border: 1px solid green; background-color: #313131;" class="MyPlugin">
     <tr>
        <td>
            <img id="img1" src="/images/1.jpg" onload="Wa_SetImgAutoSize(this)" />
        </td>
        <td>
            <img id="img2" src="/images/2.jpg" onload="Wa_SetImgAutoSize(this)"  />
        </td>
        <td>
            <img id="img3" src="/images/3.jpg" onload="Wa_SetImgAutoSize(this)"  />
        </td>
     </tr>
     <tr>
         <td>
           <img id="img4" src="/images/4.jpg" onload="Wa_SetImgAutoSize(this)" />
         </td>
         <td>
           <img id="img5" src="/images/5.jpg" onload="Wa_SetImgAutoSize(this)" />
         </td>
       <td>
        <img id="img6" src="/images/6.jpg" onload="Wa_SetImgAutoSize(this)" />
       </td>
     </tr>
     <tr>
        <td>
         <img id="img7" src="/images/7.jpg" onload="Wa_SetImgAutoSize(this)"  />
        </td>
        <td>
         <img id="img8" src="/images/8.jpg" onload="Wa_SetImgAutoSize(this)"  />
        </td>
          <td></td>
     </tr>
    </table>

由於上面這個寫法是直接在img上綁onload事件,當完成時執行修改大小的function

因此幾乎百分之百可以執行成功。但因為我不想一個tag一個tag去綁事件,並且想寫成

plugin的方式,目前還沒有想到好的解法。

剛剛問了同事,他說不要把方法寫在$(function(){…})裡面,直接寫在img的最下面,如:

image

經過測試之後,果然成功了。

附上我自製的Plugin,有興趣的可以玩玩看。MyPlugin.zip (只有js檔,沒有照片喔..)