Thursday, January 15, 2009 - 文章

jQuery 1.3來了!!

jQuery於2009/01/14釋出1.3版!!

看了一下發行文件,這次的改版有幾大特色:

  • Selector引擎大換血:
    代號為Sizzle的新版引擎,比前一個版本1.2.6速度提高49%,跟Prototype、MooTools、Dojo相比,目前jQuery1.3是最快的。值得一提的是,Sizzle是個獨立Selector引擎,並非jQuery獨有,未來在其他AJAX Framework裡也可以看到它的身影。
  • Live Events:
    以往在使用jQuery .bind()時只能侷限於設定當下已存在的元素,而live()則可以包含未來!!
    例如: 當我們宣告在所有".clsClick"元素上用live()綁上click事件,意思是將來才出現的".clsClick"也將適用!! 因此如下例中,BBB是live()後才加上class="clsClick",一樣會對click有反應。live()省去了過去元素搬家或新增時總要反覆重bind的煩人工程,是一大突破。

<script type="text/javascript">
    $(function() {
        $(".clsClick").live("click", function() { alert("Clicked!"); });
        $("div").addClass("clsClick");
    });
</script>
<div class="clsClick">AAA</div>
<div>BBB</div>

  • jQuery.Event重構:
    jQuery的Event物件重新改寫過,加入更多W3C對事件物件的定義,當然,可跨瀏覽器使用。
  • HTML字串轉元素效率提升:
    jQuery裡"給HTML字串變元素"的特性(例如用於after(), append()時)十分好用,但效率不佳,常變成效能上的瓶頸,1.3版重新改寫後,速度提高六倍。另外,建立DOM物件如$("<script />")的速度現在跟$(document.createElement("script"))一樣快。
  • Offset重寫:
    求取元素座標的函數offset()重寫過了,排除了跨瀏覽器的問題,而且也快了三倍。
  • 不再使用Browser版本判別技術:
    為了解決跨瀏覽器的問題,傳統的解法會偵測瀏覽器版本,假設某一版本特性如何如何,再見招拆招。但如果瀏覽器改版或是修掉某個Bug,見招拆招的邏輯肯定就得再調整,不勝其擾。因此jQuery試圖用另一種概念,以偵測瀏覽器是否支援某個功能代替由瀏覽器版本推論其支援功能,如此能更貼近實務也更有彈性。新物件jQuery.support提供了瀏覽器是否支援某些特性的資訊,但jQuery.browser仍會持續存在。

另外,1.3版本有些更動是換版時必須修改程式配合的:

  • 如果還有Selector [@attr]的古早寫法,請將@移除
  • 使用jQuery觸發的事件,會沿著parents(),Bubble-Up到整個DOM Tree。如以下的例子: jquery-1.2.6.js時只會alert('dIn'),但若用的是jquery-1.3.js,則會依序看到dIn, dMid, dOut。
    <script type="text/javascript">
        $(function() {
            $("#TestZone div").click(function() { alert(this.id); });
            $("#dIn").click();
        });
    </script>
    <div id="TestZone">
    <div id="dOut"><div id='dMid'><div id="dIn">IN</div></div></div>
    </div>
  • jQuery.isFunction()基於效能及簡單化修改邏輯,內建函數(如alert)及DOM方法(如getAttribute())可能不被判定為函數。
  • $("a,b,c")傳回的結果改為一律依元素在文件中的順序,不再受a,b,c排列的影響。
  • trigger/triggerHandler不再接受放在陣列中的event物件,請改為直接傳入。另外,未寫在文件中的函數extra已刪除。
  • jQuery.event.trigger不再傳回Handler傳回的物件,而改為傳回true/false。
  • 請使用Standards Mode檢視使用jQuery的網頁,在Quirks Mode時可能會有問題。

最後再整理一下1.3版的一些補充特色:

  • Selector :not()支援複合式語法,例如: :not(a,b), :not(div a)現在都可以用了。
  • .toggleClass("className", true/false); 可以依條件設定或取消。
  • .closest( selector )在父系元素中找到最近的特定元素,例如: 找到包住元素的最內層tr,過去我常寫成.parents("tr:first"),現在可以直接用.closest("tr")
  • .is()支援複合式語法,例如: .is("div a")
  • .show()/.hide()改寫過,加快2.5倍。
  • show/hide/toggle/slideDown/slideUp/slideToggle除了width, height, opacity變化外,又多加了margin與padding,動畫效果也較為順暢。
  • .toggle(true/false)依條件決定show/hide,就是之前有篇文章討論條件化show/hide時所肖想的功能,現在內建了。
  • jQuery.fx.off可以用來關閉動畫過程特效,省略炫目的視覺效果讓網頁在效能不佳的裝置上能操作得更順暢一些。
  • Ajax settings中多了dataFilter callback可以用來過濾傳回內容,排除一些有害或無用的內容。
  • Ajax settings多了xhr可傳入自訂的XMLHttpRequest物件,方便開發者做進階操控。
  • Ajax/load傳參數給server時,原本只能給key/value,現也可直接給字串當參數
  • jQuery.isArray()新函數,可以用來檢測是否為陣列。

注意: 由於官方版的jquery-1.3-vsdoc.js還未釋出,因此在Visual Studio 2008中使用jQuery 1.3,Javascript Intellisense會有問題,不過不到24小時就已有強者釋出了解決方案,急用的人可以到Jamse的Blog下載jQuery 1.3 intellisense header file存成jquery-1.3-vsdoc.js頂著用。

CODE-動態依序載入JS

最近在翻修以前寫的控件(Web Control),其中有不少操作互動要靠Javascript處理。

當初還不懂jQuery(更精準點說,是jQuery還沒出生),乖乖用Javascript一行行把功能堆出來。用慣了jQuery後,這回要改寫翻新功能,說實在的,我已喪失直接用Javascript Hard-Code的耐性。就好像跟過大哥,體驗過拿手槍汽油彈在街頭火拼的爽快後,就很難再脫離幫派回去過撿石頭木棍跟人打架的生活。(這比喻一整個怪 >_<)

不過,我遇到了一個難題是,由於控件會被其他開發者引用,是屬於被支配、被指使的人頭角色,無法主控網頁的結構,因此要引用jQuery前必須確認網頁有include jquery.js。比較消極的做法是要求開發者在引用控件時一定要自行Include控件用到的幾個js,不然控件就出錯給你看以示薄懲。

我的野心稍微大一點,希望控件可以聰明地見機行事,若網頁已經載入必要的js,就不必多事,直接給它用下去就對了;否則控件要能自行載入所需的js,以供後續使用。

要實現這個理想,有三個重點: 1) 偵測必要的js是否已載入完成 2) 使用Javascript載入js 3) 多個js必須依序載入(例如: 先jquery.js再jquery.blockUI.js)。

針對1),我們可以檢測特定物件/函數是否存在(例如:typeof jQuery != "undefined")加以判斷。動態載入JS先前有討論過,也不是難事。

第3點比較麻煩,研究了一下,IE似乎無法支援<script>的onload事件,不過我有在網路上找到高人提出的解決方案,利用setInterval持續檢查特定物件是否存在以判定載入完成並觸發後續作業,這樣就可以達成依序逐一載入的目標。(其中interval變數巧妙地運用了Closure技巧,讓我大開眼界。好用的Javascript Closure以後再專文介紹)

綜合上述的研究,我寫成以下的範例:

(function() {
    function importJS(src, look_for, onload) {
        var s = document.createElement('script');
        s.setAttribute('type', 'text/javascript');
        s.setAttribute('src', src);
        if (onload) wait_for_script_load(look_for, onload);
        if (eval("typeof " + look_for) == 'undefined') {
            var head = document.getElementsByTagName('head')[0];
            if (head) head.appendChild(s);
            else document.body.appendChild(s);
        }
    }
    function wait_for_script_load(look_for, callback) {
        var interval = setInterval(function() {
            if (eval("typeof " + look_for) != 'undefined') {
                    clearInterval(interval);
                    callback();      
                }
            }, 50);
    }
    importJS("somePath/jquery-1.2.6.js", "jQuery", function() {
        importJS("somePath/jquery.blockUI.js", "jQuery.blockUI", function() {
            $.blockUI({ message: "<span>Done!</span>" });
        });
    });
})();

註: 最外層我包了一個(function() { ... })();,由於匿名函數的封裝,其中使用的importJS, wait_for_script_load等函數名稱只會這段空間中有效,不會與網頁其他地方的函數命名衝突,理由是不希望因為插入控件而干擾到網頁其他部分,我認為這也算控件品質的衡量指標之一。

搜尋

Go

<January 2009>
SunMonTueWedThuFriSat
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567
 
RSS
【工商服務】
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


BlogLook Score and Rank

Syndication