<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" 
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>網站製作學習誌-JavaScript</title>
<link>http://blog.roodo.com/jaceju/archives/cat_13834.html</link>
<description>
首頁
讀者留言版
管理介面












_uacct = &quot;UA-450710-1&quot;;
urchinTracker();
</description>
<language>zh-tw</language>
<generator>Roodo Blog System</generator>
<copyright>All Rights Reserved</copyright>
<atom:link href="http://blog.roodo.com/jaceju/archives/cat_13834.xml" rel="self" type="application/rss+xml" />
<item>
	<title>[JavaScript] 五分鐘小教室 - 不重複送出 Ajax Request</title>
	<description><![CDATA[
	這次在設計購物車時，遇到了以下的介面：

客戶的需求是在按下「 + 」 或「 - 」時，要以 Ajax 發送更新的數量到後端系統去驗算；每按一次「 + 」 或「 - 」，就要送出一次 Ajax Request。
可是這時候問題就來啦，如果數量要 10 個的話就要連續按 10 次「 + 」，也會連續發送 10 次的 Ajax Request ；這樣不但會浪費珍貴的網路頻寬，更不用說會造成後端系統的負擔。 
怎麼解決呢？其實方法很多，而這裡我採用最簡單的 setTimeout 和 clearTimeout 。程式如下：
var sending = null;

var _formSubmit = function () {
    alert('Form submited!');
};

var _doAjaxPost = function () {
    if (sending !== null) {
        clearTimeout(sending);
        sending = null;
    }
    sending = setTimeout(_formSubmit, 1000);
};

var plusQuantity = function () {
    // ... 執行增加數量的動作 ...
    _doAjaxPost();
    return false;
};

var minusQuantity = function () {
    // ... 執行減少數量的動作 ...
    _doAjaxPost();
    return false;
};

$(function () {
    // 增加數量
    $('a.plus').click(plusQuantity);

    // 減少數量
    $('a.minus').click(minusQuantity);
});
註：這裡我大量使用了 jQuery 的功能。 
想法很簡單，就是當我們按下「 + 」 或「 - 」時，要隔一秒才會送出 Ajax Request ；而在這一秒內如果再次按下「 + 」 或「 - 」，那麼就重新計時。 
因此程式的主要重點在 _doAjaxPost 這個函式以及全域變數： sending ；當第一次呼叫 _doAjaxPost 時 sending 還是 null ，這時我們利用 setTimeout 開始計時，並將計時器指定給 sending 這個變數。而當第二次呼叫時， sending 變數已經不為空值，因此我們再利用 clearTimeout 將它清除，並重設為 null 以達到重新計時的目的。
是不是很簡單呢？
如果各位有更好的作法，也歡迎分享~ 

	]]>
	</description>
	<content:encoded><![CDATA[
	<p>這次在設計購物車時，遇到了以下的介面：</p>
<p class="image"><img src="http://www.jaceju.net/resources/norepeat_ajax/ajax_interface.gif" alt="" width="64" height="50" /></p>
<p>客戶的需求是在按下「 + 」 或「 - 」時，要以 Ajax 發送更新的數量到後端系統去驗算；每按一次「 + 」 或「 - 」，就要送出一次 Ajax Request。</p>
<p>可是這時候問題就來啦，如果數量要 10 個的話就要連續按 10 次「 + 」，也會連續發送 10 次的 Ajax Request ；這樣不但會浪費珍貴的網路頻寬，更不用說會造成後端系統的負擔。 </p>
<p>怎麼解決呢？其實方法很多，而這裡我採用最簡單的 setTimeout 和 clearTimeout 。程式如下：</p>
<pre><code><strong>var sending = null;</strong>

var _formSubmit = function () {
    alert('Form submited!');
};

<strong>var _doAjaxPost = function () {</strong>
    <strong>if (sending !== null) {</strong>
        <strong>clearTimeout(sending);</strong>
        <strong>sending = null;</strong>
    <strong>}</strong>
    <strong>sending = setTimeout(_formSubmit, 1000);</strong>
<strong>};</strong>

var plusQuantity = function () {
    // ... 執行增加數量的動作 ...
    _doAjaxPost();
    return false;
};

var minusQuantity = function () {
    // ... 執行減少數量的動作 ...
    _doAjaxPost();
    return false;
};

$(function () {
    // 增加數量
    $('a.plus').click(plusQuantity);

    // 減少數量
    $('a.minus').click(minusQuantity);
});</code></pre>
<p class="note">註：這裡我大量使用了 <a href="http://jquery.com/">jQuery</a> 的功能。 </p>
<p>想法很簡單，就是當我們按下「 + 」 或「 - 」時，要隔一秒才會送出 Ajax Request ；而在這一秒內如果再次按下「 + 」 或「 - 」，那麼就重新計時。 </p>
<p>因此程式的主要重點在 _doAjaxPost 這個函式以及全域變數： sending ；當第一次呼叫 _doAjaxPost 時 sending 還是 null ，這時我們利用 setTimeout 開始計時，並將計時器指定給 sending 這個變數。而當第二次呼叫時， sending 變數已經不為空值，因此我們再利用 clearTimeout 將它清除，並重設為 null 以達到重新計時的目的。</p>
<p>是不是很簡單呢？</p>
<p>如果各位有更好的作法，也歡迎分享~ </p>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/6643083.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/6643083.html</guid>
	<category>JavaScript</category>
	<pubDate>Sat, 02 Aug 2008 17:32:50 +0800</pubDate>
</item>
<item>
	<title>[jQuery] 自製 jQuery Plugin - Part 2</title>
	<description><![CDATA[
	在 Part 1 我們看到如何建立一個 jQuery Plugin 的雛形，也讓它能夠做一些簡單的動作了。只是這個 Plugin 似乎沒什麼太大的用途，所以接下來我們就來寫個真正能用的東西。
簡單的頁籤功能
要舉個簡單又實用的教學用例子，一直都是非常困難的事情。經過多次的思考與挑選，我決定用頁籤功能 (Tab) 來當做本文練習的重點。 
當然 jQuery 已經有一些 Tab 相關的 Plugin 了，而且基於不重造輪子的理念下，我們似乎不應該自己動手；不過站在學習的角度下，如果我們自己實作一個簡單的頁籤的話，將會有助於瞭解 jQuery Plugin 的設計過程。
以下先來瞭解我們需要的功能，再來想想看怎麼實作它。
首先我們的頁籤大概會長成這樣子：



基本上我們要的效果就是在點選上面的 TAB1 、 TAB2 及 TAB3 時，底下的文字區塊會跟著切換，這就是最簡單的頁籤功能了。  
頁面結構
在 HTML 的部份也非常簡單，基本上是一個 UL 清單 (div.tabs ul) 加上三個 DIV 區塊 (div.tabBlock) ，最後再用一個大 DIV 區塊 (div#mytab) 把它們包起來。
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
&lt;title&gt;jQuery TEST&lt;/title&gt;
&lt;link href=&quot;mytab.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;div id=&quot;mytab&quot;&gt;
&lt;div class=&quot;tabs&quot;&gt;
&lt;ul&gt;
&lt;li class=&quot;active&quot;&gt;&lt;a href=&quot;#tab1&quot;&gt;&lt;span&gt;TAB1&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#tab2&quot;&gt;&lt;span&gt;TAB2&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#tab3&quot;&gt;&lt;span&gt;TAB3&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;div id=&quot;tab1&quot; class=&quot;tabBlock&quot;&gt;
有時候寫 jQuery 時，常會發現一些簡單的效果可以重複利用。只是每次用 Copy &amp;amp; Paste 大法似乎不是件好事，有沒有什麼方法可以讓我們把這些效果用到其他地方呢？
&lt;/div&gt;
&lt;div id=&quot;tab2&quot; class=&quot;tabBlock&quot;&gt;
沒錯，就是用 jQuery 的 Plugin 機制。不過 jQuery 的 Plugin 機制好像很難懂？其實一點也不。以下我用最簡單的方式來為大家解說如何自製一個簡單的 Plugin 。
&lt;/div&gt;
&lt;div id=&quot;tab3&quot; class=&quot;tabBlock&quot;&gt;
當然在此之前，你得先瞭解 JavaScript 的 class 、 object 、 variables scope 還有 anonymous function 等基礎...
&lt;/div&gt;
&lt;/div&gt;

&lt;script type=&quot;text/javascript&quot; src=&quot;jquery/1.2.3.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;jquery/mytab.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(function () {
    $('#mytab').mytab();
});
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
當然別忘了把 JavaScript 檔案引入，這裡我先把 mytoolbox.js 改為 mytab.js ，因為我們要做的是頁籤。 
而頁籤樣式的部份則以是 CSS 來完成，請把它存檔並命名為 mytab.css ：
div.tabBlock {
clear:both;
margin-top:-1px;
border:1px solid #CCC;
padding:5px;
}
div.tabs {
margin-bottom:-1px;
overflow:hidden;
}
div.tabs ul {
margin:0;
padding:0;
list-style:none;
}
div.tabs ul li {
float:left;
height:25px;
margin:0 3px;
line-height:25px;
font-size:9pt;
border:1px solid #CCC;
overflow:hidden;
}
div.tabs ul li a {
display:block;
padding:3px;
color:#000;
text-decoration:none;
}
div.tabs ul li.active a,
div.tabs ul li a:hover {
color:#FFF;
background:#999;
}
這裡我們就不深究 CSS 怎麼做的了，有興趣的朋友請自行參考相關書籍。
準備 Plugin 樣版 
現在把 Part 1 的 mytoolbox.js 複製為 mytab.js ，然後稍做修改，如下： 
;(function($) {

$.fn.mytab = function(settings) {
    var _defaultSettings = {};
    var _settings = $.extend(_defaultSettings, settings);
    var _handler = function() {
        // 從這裡開始
    };
    return this.each(_handler);
};

})(jQuery);
從上面的程式中可以看到我把 _defaultSettings 的內容清掉了，因為我們暫時用不到特別的設定。然後我把給 each 方法用的 callback 獨立為 _handler 函式，因為後面我們要做的動作大部份都會在這裡發生。 
呈現頁籤下的區塊
在套上 CSS 後，我們會看到三個 div.tabBlock 區塊同時都顯示出來了，這樣做的目的其實是為了當瀏覽器沒有開 JavaScript 時還能呈現資訊。而在開啟了 JavaScript 後，我希望只呈現第一個 div.tabBlock 區塊，這時我們就可以利用 jQuery 來完成：
    var _handler = function() {
        $('div.tabBlock', this).hide().eq(0).show();
    };
在解釋原理之前，先回頭看一下 HTML 頁面呼叫  Plugin 的地方，你會發現我把 Plugin 套用在 div#mytab 這個元素上，所以在 _handler 裡的 this 其實是指向 div#mytab 。
 瞭解 this 代表的意義後，接著回到 _handler 中，我們就可以知道第一行的 $('div.tabBlock', this) 其實就是指抓取 div#mytab 底下的三個 div.tabBlock 元素。所以第一行我們先把所有的 div.tabBlock 隱藏起來，然後利用 .eq(0).show() 把第一個 div.tabBlock 顯示出來。
讓頁籤動起來
接著我們先讓頁籤在點選時能夠切換它的反白狀態，而反白的效果我們已經定義 CSS 裡了，也就是讓 LI 的 class 變成 active 即可： 
    var _handler = function() {
        $('div.tabBlock', this).hide().eq(0).show();
        $('div.tabs li a', this).click(function () {
            $('div.tabs li').removeClass('active');
            $(this).parent('li').toggleClass('active');
            return false;
        });
    };
這邊的原理也很簡單，首先先讓所有 div.tabs li 都移除反白效果，然後再對我們按的連結的上一層 LI 元素套上 active 。注意這裡也有個 this ，它代表的是目前點選的頁籤連結。
最後我們要 return false ，以阻止 click 事件被往上傳遞。
現在點選看看頁籤連結，是不是能反白了呢？
註：滑過頁籤會呈現反白這個效果也是定義在 CSS 裡，試著找找看吧。
記住「這個」
在繼續完成效果前，有個問題我得先說明一下。雖然我們在測試頁面上只佈置了一個 Tab 元件，不過很難保證頁面上不會有其他地方也會用到頁籤效果，這時我們的 Plugin 可能會產生副作用。 
問題出在 $('div.tabs li').removeClass('active') 這行，因為我們不能確定頁面其他地方是不是也有有元素符合 $('div.tabs li') 。所以我在這裡應該要明確指定這些 LI 元素應該屬於那個元素，也就是 $('div.tabs li a', this) 的 this (即 div#mytab ) 。
不過在 click 方法指定的匿名函式中， this 又指到 a 元素，而不是我們要的 div#mytab ；那麼有什麼方法能在 click 中找到 div#mytab 呢？總不能把 div#mytab 寫死在 Selector 中吧？其實方法很簡單，就是在 click 外先定義一個新變數指向外部的 this ：
    var _handler = function() {
        var container = this; // 加入這行，並將以下表示 div#mytab 的 this 改為 container
        $('div.tabBlock', container).hide().eq(0).show();
        $('div.tabs li a', container).click(function () {
            $('div.tabs li', container).removeClass('active');
            $(this).parent('li').toggleClass('active'); // 這個 this 不用動，它表示 a 元素
            return false;
        });
    };
因為在 click 的匿名函式會繼承外部的作用域，使得 container 的 scope 得以存在於 click 的 callback 裡；因此我們就能放心的使用 container 來表示 div#mytab 了。 
註：在 click 裡的 callback 又有另一個名稱： closure ，因為它用到了外部 function 所定義的變數。
切換對應的區塊
接著繼續完成我們要的功能，也就是切換頁籤對應的區塊。
這裡我用了連結錨點的技巧，這個技巧本身有個優點：就是當 JavaScript 被禁用時，錨點還能正常動作。而錨點的名稱剛好就是頁籤所對應的內容區塊 ID ，這就方便我們找到要顯示的內容區塊。 
程式碼如下：
    var _handler = function() {
        var container = this;
        $('div.tabBlock', container).hide().eq(0).show();
        $('div.tabs li a', container).click(function () {
            $('div.tabs li', container).removeClass('active');
            $(this).parent('li').toggleClass('active');
            $('div.tabBlock', container).hide(); // 先全部藏起來
            var id = (String(this.href).match(/(#.+)$/))[1]; // 只抓對應的 tabBlock id
            $(id).show(); // 顯示對應的 tabBlock
            return false;
        });
    };
原理一樣很簡單，當按下頁籤連結時，先隱藏所有內容區塊 (div.tabBlock) ，然後取得連結的 href 位址中的錨點名稱，以顯示頁籤所對應的內容區塊。不過這裡要注意一點，那就是瀏覽器通常會幫我們在錨點名稱前加入目前完整的網址；因此我這裡便使用正規式來取得帶井字號的錨點名稱，也剛好直接讓 jQuery 使用。
減少多餘的查詢
再看一次程式，我發現有個地方重複查詢了兩次，那就是 $('div.tabBlock', container) ；第一次是在我們只顯示第一個內容區塊時，而第二次則在點選連結時要隱藏所有內容區塊時。這裡我們可以利用暫存變數來解決： 
    var _handler = function() {
        var container = this;
        var $tabBlocks = $('div.tabBlock', container); // 加入這行
        $tabBlocks.hide().eq(0).show(); // 改用 $tabBlocks
        $('div.tabs li a', container).click(function () {
            $('div.tabs li', container).removeClass('active');
            $(this).parent('li').toggleClass('active');
            $tabBlocks.hide(); // 改用 $tabBlocks
            var id = (String(this.href).match(/(#.+)$/))[1];
            $(id).show();
            return false;
        });
    };
不過也不是每個重複的查詢都要用暫存變數，因為假設當你在 Plugin 運作的過程中，對 div.tabBlock 有進行增減的話，那麼重複再查一次就是必要的動作了，這樣才能確保我們抓到正確數量的元素集。 
到這裡我們的 mytab.js 初版算是完成了，試試看它是不是依照我們的要求正確動作呢？
加強 Plugin
雖然我們的 Plugin 已經可以動作了，但其實還是有些地方可以加強；而加入這些功能其實就是為了讓 Plugin 能更有彈性，以應付各種不同的狀況。
這裡我簡單介紹兩個加強的功能：
由外部決定 class 
我們希望可以指定 active 的名稱，讓外部可以自行決定。我們在 _defaultSettings 中多定義了一個 activeClass 項目，然後把程式裡的所有 'active' 改為 _settings.activeClass 。程式碼修改如下：
$.fn.mytab = function(settings) {
    var _defaultSettings = {
        activeClass: 'active'
    };
    var _settings = $.extend(_defaultSettings, settings);
    var _handler = function() {
        var container = this;
        var $tabBlocks = $('div.tabBlock', container);
        $tabBlocks.hide().eq(0).show();
        $tabLinks.click(function () {
            $tabLists.removeClass(_settings.activeClass);
            $(this).parent('li').toggleClass(_settings.activeClass);
            $tabBlocks.hide();
            var id = (String(this.href).match(/(#.+)$/))[1];
            $(id).show();
            return false;
        });
    };
    return this.each(_handler);
};
同樣的原理，我們可以更改 div.tabs 和 div.tabBlock 的 class 名稱，這邊我留給各位自行試試。
自動切換內容區塊 
現在我希望進入頁面時，能讓內容區塊自動跳到我指定的頁籤。這裡我有兩種方式可以指定：由網址決定以及用 Server 程式決定。
以網址決定就是我們在瀏覽器的網址列的網址後面再加上錨點名稱，例如：
http://localhost/mytab.htm#tab2
這個網址可以由外部的網頁以連結的方式指定，這樣的話進入我們這個頁籤畫面時，我們就可以依照這個錨點來決定要顯示的內容區塊。程式很簡單：
    var _handler = function() {
        var container = this;
        var $tabBlocks = $('div.tabBlock', container);

        // 加入以下這段
        var matches = (String(location.href).match(/(#.+)$/));
        if (null !== matches) {   // 有找到網址錨點的話就切換內容
            var id = matches[1];
            $tabBlocks.hide();    // 先把全部的內容區塊藏起來
            $(id).show();         // 顯示錨點對應的內容區塊
                                  // 將對應的頁籤連結反白
            $('div.tabs li', container).removeClass(_settings.activeClass);
            $('div.tabs li a', container).each(function () {
                if (-1 !== String(this.href).indexOf(id)) {
                    $(this).parent('li').toggleClass(_settings.activeClass);
                }
            });
        } else {
            $tabBlocks.hide().eq(0).show();
        }

        // ... 略 ...
    };
原理就是透過錨點來顯示對應的內容區塊，再跟著把對應頁籤連結反白即可；如果沒有指定錨點的話，就顯示第一個內容區塊。
當然別忘了重構，把多餘的查詢動作用暫存變數取代：
var _handler = function() {
        var container = this;
        var $tabBlocks = $('div.tabBlock', container);
        var $tabLists = $('div.tabs li', container);
        var $tabLinks = $('div.tabs li a', container);

        var matches = (String(location.href).match(/(#.+)$/));
        if (null !== matches) {
            var id = matches[1];
            $tabBlocks.hide();
            $(id).show();
            $tabLists.removeClass(_settings.activeClass);
            $tabLinks.each(function () {
                if (-1 !== String(this.href).indexOf(id)) {
                    $(this).parent('li').toggleClass(_settings.activeClass);
                }
            });
        } else {
            $tabBlocks.hide().eq(0).show();
        }

        $tabLinks.click(function () {
            $tabLists.removeClass(_settings.activeClass);
            $(this).parent('li').toggleClass(_settings.activeClass);
            $tabBlocks.hide();
            var id = (String(this.href).match(/(#.+)$/))[1];
            $(id).show();
            return false;
        });
    };
回到主題，我們的另外一種指定內容區塊的方式就是在 Server 端輸出 HTML 時，就先決定好 active 的 LI 元素了。假設現在頁籤部份的 HTML 如下： 
&lt;div class=&quot;tabs&quot;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#tab1&quot;&gt;&lt;span&gt;TAB1&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li class=&quot;active&quot;&gt;&lt;a href=&quot;#tab2&quot;&gt;&lt;span&gt;TAB2&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#tab3&quot;&gt;&lt;span&gt;TAB3&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
現在 TAB2 這個 LI 元素的 class 是 active ，那麼我們應該怎麼自動切換到對應的內容區塊呢？很簡單，就讓 li.active 底下的 a 「點下去」就可以了。程式如下：
    var _handler = function() {
        // ... 略 ...

        $tabLinks.click(function () {
            $tabLists.removeClass(_settings.activeClass);
            $(this).parent('li').toggleClass(_settings.activeClass);
            $tabBlocks.hide();
            var id = (String(this.href).match(/(#.+)$/))[1];
            $(id).show();
            return false;
        });

        // 加入這段
        var $activeLink = $('div.tabs li.' + _settings.activeClass + ' &gt; a', container);
        if (0 !== $activeLink.size()) {
            $activeLink.trigger('click');
        }
    };
原理就是在我們指定好頁籤連結的 click 事件後，再觸發 li.active 底下的連結的 click 事件即可，很簡單吧。 
測試再測試
以上我們都只在單一個頁籤元件上測試而已 (也就是 div#mytab ) ，但一般來說大部份的 Plugin 應該要能在頁面中被套用到多個元件上；換句話說就是頁面上會好幾個有頁籤的區塊，所以這裡我們得測試這個可能發生的狀況。
我在原來的 div#mytab 底下再加入一個 div#mytab2 ，內容和 div#mytab 差不多，只是把 #tab1, #tab2, #tab3 改成 #tab4, #tab5, #tab6 而已：
&lt;div id=&quot;mytab2&quot;&gt;
&lt;div class=&quot;tabs&quot;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#tab4&quot;&gt;&lt;span&gt;TAB4&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li class=&quot;active&quot;&gt;&lt;a href=&quot;#tab5&quot;&gt;&lt;span&gt;TAB5&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#tab6&quot;&gt;&lt;span&gt;TAB6&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;div id=&quot;tab4&quot; class=&quot;tabBlock&quot;&gt;
aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa
&lt;/div&gt;
&lt;div id=&quot;tab5&quot; class=&quot;tabBlock&quot;&gt;
bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb
&lt;/div&gt;
&lt;div id=&quot;tab6&quot; class=&quot;tabBlock&quot;&gt;
ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc
&lt;/div&gt;
&lt;/div&gt;
然後我也為 div#mytab 和 div#mytab2 加入一組 class=&quot;mytab&quot; ：
&lt;div id=&quot;mytab&quot; class=&quot;mytab&quot;&gt;
... 略 ...
&lt;div id=&quot;mytab2&quot; class=&quot;mytab&quot;&gt;
現在我們把 HTML 頁面上套用 Plugin 的部份稍作修改，也就是把 id 換成 class ：
$(function () {
    $('.mytab').mytab();
});
然後我們重新瀏覽一下，一切看起來很正常。直到我測試了用網址錨點來自動切換內容區塊時...出現了下圖的奇怪現象：

原因出在我們發現錨點時，就會先隱藏所有內容區塊，然後才顯示錨點對應的內容區塊；但是這樣就會使得沒有錨點對應的內容區塊通通不顯示，出現了上圖的狀況。
怎麼辦？其實也很簡單，就是將該頁籤元件所擁有的頁籤連結對應的錨點先記下來，然後找找看網址描點有沒有在這裡面，有的話才做上面的動作，不然就一定要顯示第一個內容區塊：
    var _handler = function() {
        var container = this;
        var $tabBlocks = $('div.tabBlock', container);
        var $tabLists = $('div.tabs li', container);
        var $tabLinks = $('div.tabs li a', container);
        var tabIdList = [];

        // 先記住所有頁籤連結對應的錨點
        $tabLinks.each(function () {
            var matches = (String(this.href).match(/(#.+)$/));
            if (null !== matches) {
                tabIdList.push(matches[1]);
            }
        });

        var matches = (String(location.href).match(/(#.+)$/));
        if (null !== matches // 錨點在列表裡的話就顯示
                &amp;&amp; -1 !== $.inArray(matches[1], tabIdList)) {
            var id = matches[1];
            $tabBlocks.hide();
            $(id).show();
            $tabLists.removeClass(_settings.activeClass);
            $tabLinks.each(function () {
                if (-1 !== String(this.href).indexOf(id)) {
                    $(this).parent('li').toggleClass(_settings.activeClass);
                }
            });
        } else {
            $tabBlocks.hide().eq(0).show();
        }

        // ... 略 ...
    };
這裡我用了最簡單 JavaScritp 的陣列，還有 jQuery 的 $.inArray 方法來解決這個問題；想想看，有沒有更方便的解法呢？ 
之後當然我們還得再多試試幾個不同的狀況，看看還有沒有需要解決的部份，這裡就留給大家試試看囉。
還有什麼
在看完以上的介紹後，我想自己寫一個 jQuery 的 Plugin 其實並不困難，困難的是我們要怎麼去完成裡面的內容。所以像是對 JavaScript 的作用域的認知、各家瀏覽器的差異、 DHTML 的基本功，還有如何去呈現效果的想像力等，這些都是在開發 jQuery Plugin 非常重要的。
另外就是一定要對程式碼做重構與測試的動作，因為它們會影響這個 Plugin 的效能與穩定性。這裡可以多參考其他 Plugin 作者的程式碼，觀察他們是如何處理效能問題；然後最好能建立一個測試頁面，把有可能遇到的使用方式儘可能地包含進來，以便測試 Plugin 的正確性。 
希望透過這兩篇簡單的教學，能讓大家能快速進入 jQuery Plugin 的世界；也希望大家如果開發了好的 Plugin 後，能不吝分享出來。
感謝大家~~謝謝收看。

	]]>
	</description>
	<content:encoded><![CDATA[
	<p>在 <a href="http://blog.roodo.com/jaceju/archives/6016309.html">Part 1</a> 我們看到如何建立一個 jQuery Plugin 的雛形，也讓它能夠做一些簡單的動作了。只是這個 Plugin 似乎沒什麼太大的用途，所以接下來我們就來寫個真正能用的東西。</p>
<h2>簡單的頁籤功能</h2>
<p>要舉個簡單又實用的教學用例子，一直都是非常困難的事情。經過多次的思考與挑選，我決定用頁籤功能 (Tab) 來當做本文練習的重點。 </p>
<p>當然 jQuery 已經有一些 Tab 相關的 Plugin 了，而且基於不重造輪子的理念下，我們似乎不應該自己動手；不過站在學習的角度下，如果我們自己實作一個簡單的頁籤的話，將會有助於瞭解 jQuery Plugin 的設計過程。</p>
<p>以下先來瞭解我們需要的功能，再來想想看怎麼實作它。</p>
<p>首先我們的頁籤大概會長成這樣子：</p>
<p class="image"><img src="http://www.jaceju.net/resources/jquery_plugin_tutorial/mytab01.jpg" alt="頁籤基本形式" /></p>
<p class="image"><img src="http://www.jaceju.net/resources/jquery_plugin_tutorial/mytab02.jpg" alt="頁籤基本形式" /></p>
<p class="image"><img src="http://www.jaceju.net/resources/jquery_plugin_tutorial/mytab03.jpg" alt="頁籤基本形式" /></p>
<p>基本上我們要的效果就是在點選上面的 TAB1 、 TAB2 及 TAB3 時，底下的文字區塊會跟著切換，這就是最簡單的頁籤功能了。  </p>
<h2>頁面結構</h2>
<p>在 HTML 的部份也非常簡單，基本上是一個 UL 清單 (div.tabs ul) 加上三個 DIV 區塊 (div.tabBlock) ，最後再用一個大 DIV 區塊 (div#mytab) 把它們包起來。</p>
<pre><code>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
&lt;title&gt;jQuery TEST&lt;/title&gt;
&lt;link href=&quot;mytab.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;

<strong>&lt;div id=&quot;mytab&quot;&gt;
&lt;div class=&quot;tabs&quot;&gt;
&lt;ul&gt;
&lt;li class=&quot;active&quot;&gt;&lt;a href=&quot;#tab1&quot;&gt;&lt;span&gt;TAB1&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#tab2&quot;&gt;&lt;span&gt;TAB2&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#tab3&quot;&gt;&lt;span&gt;TAB3&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;div id=&quot;tab1&quot; class=&quot;tabBlock&quot;&gt;
有時候寫 jQuery 時，常會發現一些簡單的效果可以重複利用。只是每次用 Copy &amp;amp; Paste 大法似乎不是件好事，有沒有什麼方法可以讓我們把這些效果用到其他地方呢？
&lt;/div&gt;
&lt;div id=&quot;tab2&quot; class=&quot;tabBlock&quot;&gt;
沒錯，就是用 jQuery 的 Plugin 機制。不過 jQuery 的 Plugin 機制好像很難懂？其實一點也不。以下我用最簡單的方式來為大家解說如何自製一個簡單的 Plugin 。
&lt;/div&gt;
&lt;div id=&quot;tab3&quot; class=&quot;tabBlock&quot;&gt;
當然在此之前，你得先瞭解 JavaScript 的 class 、 object 、 variables scope 還有 anonymous function 等基礎...
&lt;/div&gt;
&lt;/div&gt;</strong>

<strong>&lt;script type=&quot;text/javascript&quot; src=&quot;jquery/1.2.3.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;jquery/mytab.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(function () {
    $('#mytab').mytab();
});
&lt;/script&gt;</strong>
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>當然別忘了把 JavaScript 檔案引入，這裡我先把 mytoolbox.js 改為 mytab.js ，因為我們要做的是頁籤。 </p>
<p>而頁籤樣式的部份則以是 CSS 來完成，請把它存檔並命名為 mytab.css ：</p>
<pre><code>div.tabBlock {
clear:both;
margin-top:-1px;
border:1px solid #CCC;
padding:5px;
}
div.tabs {
margin-bottom:-1px;
overflow:hidden;
}
div.tabs ul {
margin:0;
padding:0;
list-style:none;
}
div.tabs ul li {
float:left;
height:25px;
margin:0 3px;
line-height:25px;
font-size:9pt;
border:1px solid #CCC;
overflow:hidden;
}
div.tabs ul li a {
display:block;
padding:3px;
color:#000;
text-decoration:none;
}
div.tabs ul li.active a,
div.tabs ul li a:hover {
color:#FFF;
background:#999;
}</code></pre>
<p>這裡我們就不深究 CSS 怎麼做的了，有興趣的朋友請自行參考相關書籍。</p>
<h2>準備 Plugin 樣版 </h2>
<p>現在把 Part 1 的 mytoolbox.js 複製為 mytab.js ，然後稍做修改，如下： </p>
<pre><code>;(function($) {

$.fn.mytab = function(settings) {
    var _defaultSettings = {};
    var _settings = $.extend(_defaultSettings, settings);
    var _handler = function() {
        <strong>// 從這裡開始</strong>
    };
    return this.each(_handler);
};

})(jQuery);</code></pre>
<p>從上面的程式中可以看到我把 _defaultSettings 的內容清掉了，因為我們暫時用不到特別的設定。然後我把給 each 方法用的 callback 獨立為 _handler 函式，因為後面我們要做的動作大部份都會在這裡發生。 </p>
<h2>呈現頁籤下的區塊</h2>
<p>在套上 CSS 後，我們會看到三個 div.tabBlock 區塊同時都顯示出來了，這樣做的目的其實是為了當瀏覽器沒有開 JavaScript 時還能呈現資訊。而在開啟了 JavaScript 後，我希望只呈現第一個 div.tabBlock 區塊，這時我們就可以利用 jQuery 來完成：</p>
<pre><code>    var _handler = function() {
        <strong>$('div.tabBlock', this).hide().eq(0).show();</strong>
    };</code></pre>
<p>在解釋原理之前，先回頭看一下 HTML 頁面呼叫  Plugin 的地方，你會發現我把 Plugin 套用在 div#mytab 這個元素上，所以在 _handler 裡的 this 其實是指向 div#mytab 。</p>
<p> 瞭解 this 代表的意義後，接著回到 _handler 中，我們就可以知道第一行的 $('div.tabBlock', this) 其實就是指抓取 div#mytab 底下的三個 div.tabBlock 元素。所以第一行我們先把所有的 div.tabBlock 隱藏起來，然後利用 .eq(0).show() 把第一個 div.tabBlock 顯示出來。</p>
<h2>讓頁籤動起來</h2>
<p>接著我們先讓頁籤在點選時能夠切換它的反白狀態，而反白的效果我們已經定義 CSS 裡了，也就是讓 LI 的 class 變成 active 即可： </p>
<pre><code>    var _handler = function() {
        $('div.tabBlock', this).hide().eq(0).show();
        <strong>$('div.tabs li a', this).click(function () {</strong>
            <strong>$('div.tabs li').removeClass('active');</strong>
            <strong>$(this).parent('li').toggleClass('active');</strong>
            <strong>return false;</strong>
        <strong>});</strong>
    };</code></pre>
<p>這邊的原理也很簡單，首先先讓所有 div.tabs li 都移除反白效果，然後再對我們按的連結的上一層 LI 元素套上 active 。注意這裡也有個 this ，它代表的是目前點選的頁籤連結。</p>
<p>最後我們要 return false ，以阻止 click 事件被往上傳遞。</p>
<p>現在點選看看頁籤連結，是不是能反白了呢？</p>
<p class="note">註：滑過頁籤會呈現反白這個效果也是定義在 CSS 裡，試著找找看吧。</p>
<h2>記住「這個」</h2>
<p>在繼續完成效果前，有個問題我得先說明一下。雖然我們在測試頁面上只佈置了一個 Tab 元件，不過很難保證頁面上不會有其他地方也會用到頁籤效果，這時我們的 Plugin 可能會產生副作用。 </p>
<p>問題出在 $('div.tabs li').removeClass('active') 這行，因為我們不能確定頁面其他地方是不是也有有元素符合 $('div.tabs li') 。所以我在這裡應該要明確指定這些 LI 元素應該屬於那個元素，也就是 $('div.tabs li a', this) 的 this (即 div#mytab ) 。</p>
<p>不過在 click 方法指定的匿名函式中， this 又指到 a 元素，而不是我們要的 div#mytab ；那麼有什麼方法能在 click 中找到 div#mytab 呢？總不能把 div#mytab 寫死在 Selector 中吧？其實方法很簡單，就是在 click 外先定義一個新變數指向外部的 this ：</p>
<pre><code>    var _handler = function() {
        <strong>var container = this; // 加入這行，並將以下表示 div#mytab 的 this 改為 container</strong>
        $('div.tabBlock', <strong>container</strong>).hide().eq(0).show();
        $('div.tabs li a', <strong>container</strong>).click(function () {
            $('div.tabs li', <strong>container</strong>).removeClass('active');
            $(this).parent('li').toggleClass('active'); // 這個 this 不用動，它表示 a 元素
            return false;
        });
    };</code></pre>
<p>因為在 click 的匿名函式會繼承外部的作用域，使得 container 的 scope 得以存在於 click 的 callback 裡；因此我們就能放心的使用 container 來表示 div#mytab 了。 </p>
<p class="note">註：在 click 裡的 callback 又有另一個名稱： closure ，因為它用到了外部 function 所定義的變數。</p>
<h2>切換對應的區塊</h2>
<p>接著繼續完成我們要的功能，也就是切換頁籤對應的區塊。</p>
<p>這裡我用了連結錨點的技巧，這個技巧本身有個優點：就是當 JavaScript 被禁用時，錨點還能正常動作。而錨點的名稱剛好就是頁籤所對應的內容區塊 ID ，這就方便我們找到要顯示的內容區塊。 </p>
<p>程式碼如下：</p>
<pre><code>    var _handler = function() {
        var container = this;
        $('div.tabBlock', container).hide().eq(0).show();
        $('div.tabs li a', container).click(function () {
            $('div.tabs li', container).removeClass('active');
            $(this).parent('li').toggleClass('active');
            <strong>$('div.tabBlock', container).hide(); // 先全部藏起來</strong>
            <strong>var id = (String(this.href).match(/(#.+)$/))[1]; // 只抓對應的 tabBlock id</strong>
            <strong>$(id).show(); // 顯示對應的 tabBlock</strong>
            return false;
        });
    };</code></pre>
<p>原理一樣很簡單，當按下頁籤連結時，先隱藏所有內容區塊 (div.tabBlock) ，然後取得連結的 href 位址中的錨點名稱，以顯示頁籤所對應的內容區塊。不過這裡要注意一點，那就是瀏覽器通常會幫我們在錨點名稱前加入目前完整的網址；因此我這裡便使用正規式來取得帶井字號的錨點名稱，也剛好直接讓 jQuery 使用。</p>
<h2>減少多餘的查詢</h2>
<p>再看一次程式，我發現有個地方重複查詢了兩次，那就是 $('div.tabBlock', container) ；第一次是在我們只顯示第一個內容區塊時，而第二次則在點選連結時要隱藏所有內容區塊時。這裡我們可以利用暫存變數來解決： </p>
<pre><code>    var _handler = function() {
        var container = this;
        <strong>var $tabBlocks = $('div.tabBlock', container); // 加入這行</strong>
        <strong>$tabBlocks</strong>.hide().eq(0).show(); <strong>// 改用 $tabBlocks</strong>
        $('div.tabs li a', container).click(function () {
            $('div.tabs li', container).removeClass('active');
            $(this).parent('li').toggleClass('active');
            <strong>$tabBlocks</strong>.hide(); <strong>// 改用 $tabBlocks</strong>
            var id = (String(this.href).match(/(#.+)$/))[1];
            $(id).show();
            return false;
        });
    };</code></pre>
<p>不過也不是每個重複的查詢都要用暫存變數，因為假設當你在 Plugin 運作的過程中，對 div.tabBlock 有進行增減的話，那麼重複再查一次就是必要的動作了，這樣才能確保我們抓到正確數量的元素集。 </p>
<p>到這裡我們的 mytab.js 初版算是完成了，試試看它是不是依照我們的要求正確動作呢？</p>
<h2>加強 Plugin</h2>
<p>雖然我們的 Plugin 已經可以動作了，但其實還是有些地方可以加強；而加入這些功能其實就是為了讓 Plugin 能更有彈性，以應付各種不同的狀況。</p>
<p>這裡我簡單介紹兩個加強的功能：</p>
<h3>由外部決定 class </h3>
<p>我們希望可以指定 active 的名稱，讓外部可以自行決定。我們在 _defaultSettings 中多定義了一個 activeClass 項目，然後把程式裡的所有 'active' 改為 _settings.activeClass 。程式碼修改如下：</p>
<pre><code>$.fn.mytab = function(settings) {
    var _defaultSettings = {
        <strong>activeClass: 'active'</strong>
    };
    var _settings = $.extend(_defaultSettings, settings);
    var _handler = function() {
        var container = this;
        var $tabBlocks = $('div.tabBlock', container);
        $tabBlocks.hide().eq(0).show();
        $tabLinks.click(function () {
            $tabLists.removeClass(<strong>_settings.activeClass</strong>);
            $(this).parent('li').toggleClass(<strong>_settings.activeClass</strong>);
            $tabBlocks.hide();
            var id = (String(this.href).match(/(#.+)$/))[1];
            $(id).show();
            return false;
        });
    };
    return this.each(_handler);
};</code></pre>
<p>同樣的原理，我們可以更改 div.tabs 和 div.tabBlock 的 class 名稱，這邊我留給各位自行試試。</p>
<h3>自動切換內容區塊 </h3>
<p>現在我希望進入頁面時，能讓內容區塊自動跳到我指定的頁籤。這裡我有兩種方式可以指定：由網址決定以及用 Server 程式決定。</p>
<p>以網址決定就是我們在瀏覽器的網址列的網址後面再加上錨點名稱，例如：</p>
<p>http://localhost/mytab.htm#tab2</p>
<p>這個網址可以由外部的網頁以連結的方式指定，這樣的話進入我們這個頁籤畫面時，我們就可以依照這個錨點來決定要顯示的內容區塊。程式很簡單：</p>
<pre><code>    var _handler = function() {
        var container = this;
        var $tabBlocks = $('div.tabBlock', container);

        <strong>// 加入以下這段</strong>
        <strong>var matches = (String(location.href).match(/(#.+)$/));</strong>
        <strong>if (null !== matches) {   // 有找到網址錨點的話就切換內容</strong>
            <strong>var id = matches[1];</strong>
            <strong>$tabBlocks.hide();    // 先把全部的內容區塊藏起來</strong>
            <strong>$(id).show();         // 顯示錨點對應的內容區塊</strong>
                                  <strong>// 將對應的頁籤連結反白</strong>
            <strong>$('div.tabs li', container).removeClass(_settings.activeClass);</strong>
            <strong>$('div.tabs li a', container).each(function () {</strong>
                <strong>if (-1 !== String(this.href).indexOf(id)) {</strong>
                    <strong>$(this).parent('li').toggleClass(_settings.activeClass);</strong>
                <strong>}</strong>
            <strong>});</strong>
        <strong>} else {</strong>
            $tabBlocks.hide().eq(0).show();
        <strong>}</strong>

        // ... 略 ...
    };</code></pre>
<p>原理就是透過錨點來顯示對應的內容區塊，再跟著把對應頁籤連結反白即可；如果沒有指定錨點的話，就顯示第一個內容區塊。</p>
<p>當然別忘了重構，把多餘的查詢動作用暫存變數取代：</p>
<pre><code>var _handler = function() {
        var container = this;
        var $tabBlocks = $('div.tabBlock', container);
        <strong>var $tabLists = $('div.tabs li', container);</strong>
        <strong>var $tabLinks = $('div.tabs li a', container);</strong>

        var matches = (String(location.href).match(/(#.+)$/));
        if (null !== matches) {
            var id = matches[1];
            $tabBlocks.hide();
            $(id).show();
            <strong>$tabLists</strong>.removeClass(_settings.activeClass);
            <strong>$tabLinks</strong>.each(function () {
                if (-1 !== String(this.href).indexOf(id)) {
                    $(this).parent('li').toggleClass(_settings.activeClass);
                }
            });
        } else {
            $tabBlocks.hide().eq(0).show();
        }

        <strong>$tabLinks</strong>.click(function () {
            <strong>$tabLists</strong>.removeClass(_settings.activeClass);
            $(this).parent('li').toggleClass(_settings.activeClass);
            $tabBlocks.hide();
            var id = (String(this.href).match(/(#.+)$/))[1];
            $(id).show();
            return false;
        });
    };</code></pre>
<p>回到主題，我們的另外一種指定內容區塊的方式就是在 Server 端輸出 HTML 時，就先決定好 active 的 LI 元素了。假設現在頁籤部份的 HTML 如下： </p>
<pre><code>&lt;div class=&quot;tabs&quot;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#tab1&quot;&gt;&lt;span&gt;TAB1&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
<strong>&lt;li class=&quot;active&quot;&gt;&lt;a href=&quot;#tab2&quot;&gt;&lt;span&gt;TAB2&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;</strong>
&lt;li&gt;&lt;a href=&quot;#tab3&quot;&gt;&lt;span&gt;TAB3&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;</code></pre>
<p>現在 TAB2 這個 LI 元素的 class 是 active ，那麼我們應該怎麼自動切換到對應的內容區塊呢？很簡單，就讓 li.active 底下的 a 「點下去」就可以了。程式如下：</p>
<pre><code>    var _handler = function() {
        // ... 略 ...

        $tabLinks.click(function () {
            $tabLists.removeClass(_settings.activeClass);
            $(this).parent('li').toggleClass(_settings.activeClass);
            $tabBlocks.hide();
            var id = (String(this.href).match(/(#.+)$/))[1];
            $(id).show();
            return false;
        });

        <strong>// 加入這段</strong>
        <strong>var $activeLink = $('div.tabs li.' + _settings.activeClass + ' &gt; a', container);</strong>
        <strong>if (0 !== $activeLink.size()) {</strong>
            <strong>$activeLink.trigger('click');</strong>
        <strong>}</strong>
    };</code></pre>
<p>原理就是在我們指定好頁籤連結的 click 事件後，再觸發 li.active 底下的連結的 click 事件即可，很簡單吧。 </p>
<h2>測試再測試</h2>
<p>以上我們都只在單一個頁籤元件上測試而已 (也就是 div#mytab ) ，但一般來說大部份的 Plugin 應該要能在頁面中被套用到多個元件上；換句話說就是頁面上會好幾個有頁籤的區塊，所以這裡我們得測試這個可能發生的狀況。</p>
<p>我在原來的 div#mytab 底下再加入一個 div#mytab2 ，內容和 div#mytab 差不多，只是把 #tab1, #tab2, #tab3 改成 #tab4, #tab5, #tab6 而已：</p>
<pre><code>&lt;div id=&quot;mytab2&quot;&gt;
&lt;div class=&quot;tabs&quot;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#tab4&quot;&gt;&lt;span&gt;TAB4&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li class=&quot;active&quot;&gt;&lt;a href=&quot;#tab5&quot;&gt;&lt;span&gt;TAB5&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#tab6&quot;&gt;&lt;span&gt;TAB6&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;div id=&quot;tab4&quot; class=&quot;tabBlock&quot;&gt;
aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa
&lt;/div&gt;
&lt;div id=&quot;tab5&quot; class=&quot;tabBlock&quot;&gt;
bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb bbb
&lt;/div&gt;
&lt;div id=&quot;tab6&quot; class=&quot;tabBlock&quot;&gt;
ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc ccc
&lt;/div&gt;
&lt;/div&gt;</code></pre>
<p>然後我也為 div#mytab 和 div#mytab2 加入一組 class=&quot;mytab&quot; ：</p>
<pre><code>&lt;div id=&quot;mytab&quot; <strong>class=&quot;mytab&quot;</strong>&gt;
... 略 ...
&lt;div id=&quot;mytab2&quot; <strong>class=&quot;mytab&quot;</strong>&gt;</code></pre>
<p>現在我們把 HTML 頁面上套用 Plugin 的部份稍作修改，也就是把 id 換成 class ：</p>
<pre><code>$(function () {
    $(<strong>'.mytab'</strong>).mytab();
});</code></pre>
<p>然後我們重新瀏覽一下，一切看起來很正常。直到我測試了用網址錨點來自動切換內容區塊時...出現了下圖的奇怪現象：</p>
<p class="image"><img src="http://www.jaceju.net/resources/jquery_plugin_tutorial/mytab04.jpg" alt="頁籤基本形式" /></p>
<p>原因出在我們發現錨點時，就會先隱藏所有內容區塊，然後才顯示錨點對應的內容區塊；但是這樣就會使得沒有錨點對應的內容區塊通通不顯示，出現了上圖的狀況。</p>
<p>怎麼辦？其實也很簡單，就是將該頁籤元件所擁有的頁籤連結對應的錨點先記下來，然後找找看網址描點有沒有在這裡面，有的話才做上面的動作，不然就一定要顯示第一個內容區塊：</p>
<pre><code>    var _handler = function() {
        var container = this;
        var $tabBlocks = $('div.tabBlock', container);
        var $tabLists = $('div.tabs li', container);
        var $tabLinks = $('div.tabs li a', container);
        <strong>var tabIdList = [];</strong>

        <strong>// 先記住所有頁籤連結對應的錨點</strong>
        <strong>$tabLinks.each(function () {</strong>
            <strong>var matches = (String(this.href).match(/(#.+)$/));</strong>
            <strong>if (null !== matches) {</strong>
                <strong>tabIdList.push(matches[1]);</strong>
            <strong>}</strong>
        <strong>});</strong>

        var matches = (String(location.href).match(/(#.+)$/));
        if (null !== matches <strong>// 錨點在列表裡的話就顯示</strong>
                <strong>&amp;&amp; -1 !== $.inArray(matches[1], tabIdList)</strong>) {
            var id = matches[1];
            $tabBlocks.hide();
            $(id).show();
            $tabLists.removeClass(_settings.activeClass);
            $tabLinks.each(function () {
                if (-1 !== String(this.href).indexOf(id)) {
                    $(this).parent('li').toggleClass(_settings.activeClass);
                }
            });
        } else {
            $tabBlocks.hide().eq(0).show();
        }

        // ... 略 ...
    };</code></pre>
<p>這裡我用了最簡單 JavaScritp 的陣列，還有 jQuery 的 $.inArray 方法來解決這個問題；想想看，有沒有更方便的解法呢？ </p>
<p>之後當然我們還得再多試試幾個不同的狀況，看看還有沒有需要解決的部份，這裡就留給大家試試看囉。</p>
<h2>還有什麼</h2>
<p>在看完以上的介紹後，我想自己寫一個 jQuery 的 Plugin 其實並不困難，困難的是我們要怎麼去完成裡面的內容。所以像是對 JavaScript 的作用域的認知、各家瀏覽器的差異、 DHTML 的基本功，還有如何去呈現效果的想像力等，這些都是在開發 jQuery Plugin 非常重要的。</p>
<p>另外就是一定要對程式碼做重構與測試的動作，因為它們會影響這個 Plugin 的效能與穩定性。這裡可以多參考其他 Plugin 作者的程式碼，觀察他們是如何處理效能問題；然後最好能建立一個測試頁面，把有可能遇到的使用方式儘可能地包含進來，以便測試 Plugin 的正確性。 </p>
<p>希望透過這兩篇簡單的教學，能讓大家能快速進入 jQuery Plugin 的世界；也希望大家如果開發了好的 Plugin 後，能不吝分享出來。</p>
<p>感謝大家~~謝謝收看。</p>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/6034507.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/6034507.html</guid>
	<category>JavaScript</category>
	<pubDate>Fri, 16 May 2008 20:53:41 +0800</pubDate>
</item>
<item>
	<title>[jQuery] 自製 jQuery Plugin - Part 1</title>
	<description><![CDATA[
	有時候寫 jQuery 時，常會發現一些簡單的效果可以重複利用。只是每次用 Copy &amp; Paste 大法似乎不是件好事，有沒有什麼方法可以讓我們把這些效果用到其他地方呢？
沒錯，就是用 jQuery 的 Plugin 機制。
不過 jQuery 的 Plugin 機制好像很難懂？其實一點也不。以下我用最簡單的方式來為大家解說如何自製一個簡單的 Plugin 。
當然在此之前，你得先瞭解 JavaScript 的 class 、 object 、 variables scope 還有 anonymous function  等基礎，這些可以參考「 JavaScript 大全」一書。
Plugin 樣版
寫 jQuery 的 Plugin 最快的方法就是拿現成的 Plugin 來改，只是在那麼多的 Plugin 中怎麼找到好的範例呢？別擔心，這邊我提供一個最簡單的範例樣版：
jQuery.fn.mytoolbox = function() {
    return this.each(function() {
    });
};
首先， mytoolbox 就是我們的 plugin 名稱，利用  jQuery.fn 我們可以將它註冊為 jQuery 的 plugin 。然後我們把  jQuery.fn.mytoolbox 指向一個匿名函式 (anonymous function) ，又稱為 callback ；而這個 callback 的內容很簡單，就是利用 jQuery 的 each 方法，來一一執行對應的動作。 
特別要注意匿名函式裡的 this 關鍵字，它會指向一個 jQuery 物件；而這個 jQuery 物件則是我們要指定的，稍後我會再進一步說明。
使用 Plugin
現在將上面的樣版存成 mytoolbox.js ，和 jquery.js 放在一起。然後建立一個 HTML 測試檔案，內容如下： 
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
&lt;title&gt;jQuery TEST&lt;/title&gt;
&lt;style type=&quot;text/css&quot;&gt;
.test {
border:1px solid #CCC;
cursor:pointer;
padding:3px;
}
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div id=&quot;test1&quot; class=&quot;test&quot;&gt;
點我！
&lt;/div&gt;
&lt;div id=&quot;test2&quot; class=&quot;test&quot;&gt;
點我！
&lt;/div&gt;
&lt;div id=&quot;debug&quot;&gt;&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;jquery/1.2.3.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;jquery/mytoolbox.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(function () {
    $('.test').mytoolbox();
});
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
首先 HTML 中引用了 jQuery 函式庫及我們寫的 Plugin 檔案，然後我在畫面上佈置了兩個 class 為 test 的 div 元素。接著我們用以下程式碼來呼叫我們的 Plugin ：
$(function () {
    $('.test').mytoolbox();
});
這邊的用意就是將上面那兩個 div 套上 mytoolbox 這個 Plugin ，這樣 Plugin 就能動了，很簡單吧？
加入動作
當然，這個 Plugin 什麼事都還沒開始做，是個空骨架而已。現在我們要為它加血添肉，讓它動起來。
先簡單在 each 的 callback 裡加入一行：
jQuery.fn.mytoolbox = function() {
    return this.each(function() {
        alert(this.id); // 加入此行
    });
};
再重新瀏覽測試用的 HTML 檔，你會發現頁面自動跳出了兩次訊息視窗，內容分別是 test1 和 test2 ；這證明了我們的 Plugin 的確有套用在 class 為 test 的兩個 div 上面。
不過現在有兩個 this ，它們是一樣的東西嗎？不，因為 scope 及觸發對象的不同，它們兩個是不同的東西。在外面的 this 是一個 jQuery 物件，指向我們指定的 $('.test') 這個物件；而 each callback 裡的 this 則是 div 元素，因為 each 是個 iterator function ，因此 alert(this.id) 會執行兩次。在第一次的 this 會指向 #test1 這個 div ，第二次則指向 #test2 這個 div 。
註：這裡我用 #test1 表示 id 為 test1 的元素。
現在我希望改成按下 div 元素後才會 alert 該元素的 id ，這要怎麼做呢？我們要改用 click 事件，做法如下：
jQuery.fn.mytoolbox = function() {
    return this.each(function() {
        jQuery(this).click(function () {
            alert(this.id);
        });
    });
};
由於 each callback 裡的 this 是 DOM 元素，所以我們要用 jQuery() 把 this 包起來，這樣才能方便指定該元素的 click 事件。現在重新瀏覽頁面，點選任何一個 div ，應該就會跳出對應的訊息視窗了。
再包一層
如果在 each 的 callback 裡會呼叫到多次的 jQuery 的話，一直寫 jQuery 這幾個字實在是很累人的一件事；而且 jQuery 不是可以簡寫成 $ 號嗎？不能直接用嗎？當然可以，只是這樣可能會和其他 JavaScript Library 發生衝突；所以我們要改用以下的方式來包覆我們的 Plugin ：
;(function($) {

$.fn.mytoolbox = function() {
    return this.each(function() {
        $(this).click(function () {
            alert(this.id);
        });
    });
};

})(jQuery);
JavaScript 可以直接用一組小括號 [()] 包覆一個匿名函式，然後後面再接一組小括號 [()]  表示呼叫這個匿名函式；而第二組小括號中就可以放置這個匿名函式的參數。所以在上面的程式碼中，我們把 Plugin 的程式碼用一個匿名函式包覆起來，然後參數就用我們常用的 $ 符號；接著在利用前述的原理，將 jQuery 這個類別導入給我們的 Plugin ，這樣我們就可以很快樂地在 Plugin 中使用我們熟悉的 $ 符號了。至於最前面的分號 (;) ，主要是考慮這個 Plugin 檔案會和其他 JS 檔合併壓縮而放進來的。
註： $ 在 JavaScript 裡是合法的變數名稱。
後面的說明我會略過這個包覆動作，在實際檔案中請別忘了加。
加入選項設定
接下來我希望讓 each 的 callback 函式能讓使用者自訂，因此我需要一個讓使用者能設定的選項。就像其他的 Plugin 一樣，我們讓我們的 mytoolbox 可以接受一個 JSON 物件：
$.fn.mytoolbox = function(settings) {

    var _defaultSettings = {
        callback: function () {
            alert(this.id);
        }
    };

    var _settings = $.extend(_defaultSettings, settings);

    return this.each(function() {
        $(this).click(_settings.callback);
    });
};
首先我們為 Plugin 加入 settings 參數，也就是一般 Plugin 常見的設定值。然後則是 _defaultSettings ，它能幫我們在使用者沒有指定任何設定值給 settings 時，還能夠提供預設的設定值。
接著我用 jQuery 提供的 extend 方法，將 settings 中有設定的值覆蓋掉 _defaultSettings 所設定的預設值，再把結果存放在 _settings 這個變數中；後面我們就會用新的 _settings 變數當做我們的設定值。
現在我們在 _settings 中指定了一個 callback 項目 (預設是用 alert ) ，然後將它指定給 div 元素的 click 觸發器。現在我要在 HTML 頁面中更改這個事件處理器，使它不再使用 alert ，而是把結果顯示在 div#debug 裡。程式如下：
$(function () {
    var debug = $('#debug');
    $('.test').mytoolbox({
        callback: function () {
            debug.html(debug.html() + this.id + '&lt;br /&gt;');
        }
    });
});
再重新瀏覽一次頁面，看看效果是不是依照我們想像的完成呢？
修改觸發事件
假設現在我們不想用 click ，而是想讓滑鼠移過就觸發 callback 呢？這時就要借重 jQuery 的 bind 方法了：
$.fn.mytoolbox = function(settings) {

    var _defaultSettings = {
        bind: 'click',
        callback: function () {
            alert(this.id);
        }
    };

    var _settings = $.extend(_defaultSettings, settings);

    return this.each(function() {
        $(this).bind(_settings.bind, _settings.callback);
    });
};
這裡我加入一個 bind 設定項目，預設是用 click 事件觸發。回到 HTML 頁面，我們改用 mouseover 來觸發 callback ：
$(function () {
    var debug = $('#debug');
    $('.test').mytoolbox({
        bind: 'mouseover',
        callback: function () {
            debug.html(debug.html() + this.id + '&lt;br /&gt;');
        }
    });
});
重新瀏覽 HTML 頁面，當滑鼠移過 div 元素時，是不是會出現對應的 id 呢？
到這裡，相信大家都應該大致瞭解如何建立一個 jQuery Plugin 了吧？接下來，我將透過實際的例子為大家介紹更多自製 jQuery Plugin 所需要注意的地方。
請觀賞 Part 2 。
參考網址

A Plugin Development Pattern 


	]]>
	</description>
	<content:encoded><![CDATA[
	<p>有時候寫 jQuery 時，常會發現一些簡單的效果可以重複利用。只是每次用 Copy &amp; Paste 大法似乎不是件好事，有沒有什麼方法可以讓我們把這些效果用到其他地方呢？</p>
<p>沒錯，就是用 jQuery 的 Plugin 機制。</p>
<p>不過 jQuery 的 Plugin 機制好像很難懂？其實一點也不。以下我用最簡單的方式來為大家解說如何自製一個簡單的 Plugin 。</p>
<p>當然在此之前，你得先瞭解 JavaScript 的 class 、 object 、 variables scope 還有 anonymous function  等基礎，這些可以參考「<a href="http://tlsj.tenlong.com.tw/WebModule/BookSearch/bookSearchViewAction.do?isbn=9789866840036&amp;sid=37518" target="_blank"> JavaScript 大全</a>」一書。</p>
<h2>Plugin 樣版</h2>
<p>寫 jQuery 的 Plugin 最快的方法就是拿現成的 Plugin 來改，只是在那麼多的 Plugin 中怎麼找到好的範例呢？別擔心，這邊我提供一個最簡單的範例樣版：</p>
<pre><code>jQuery.fn.mytoolbox = function() {
    return this.each(function() {
    });
};</code></pre>
<p>首先， mytoolbox 就是我們的 plugin 名稱，利用  jQuery.fn 我們可以將它註冊為 jQuery 的 plugin 。然後我們把  jQuery.fn.mytoolbox 指向一個匿名函式 (anonymous function) ，又稱為 callback ；而這個 callback 的內容很簡單，就是利用 jQuery 的 each 方法，來一一執行對應的動作。 </p>
<p>特別要注意匿名函式裡的 this 關鍵字，它會指向一個 jQuery 物件；而這個 jQuery 物件則是我們要指定的，稍後我會再進一步說明。</p>
<h2>使用 Plugin</h2>
<p>現在將上面的樣版存成 mytoolbox.js ，和 jquery.js 放在一起。然後建立一個 HTML 測試檔案，內容如下： </p>
<pre><code>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
&lt;title&gt;jQuery TEST&lt;/title&gt;
&lt;style type=&quot;text/css&quot;&gt;
.test {
border:1px solid #CCC;
cursor:pointer;
padding:3px;
}
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
<strong>&lt;div id=&quot;test1&quot; class=&quot;test&quot;&gt;</strong>
<strong>點我！</strong>
<strong>&lt;/div&gt;</strong>
<strong>&lt;div id=&quot;test2&quot; class=&quot;test&quot;&gt;</strong>
<strong>點我！</strong>
<strong>&lt;/div&gt;</strong>
<strong>&lt;div id=&quot;debug&quot;&gt;&lt;/div&gt;</strong>
<strong>&lt;script type=&quot;text/javascript&quot; src=&quot;jquery/1.2.3.js&quot;&gt;&lt;/script&gt;</strong>
<strong>&lt;script type=&quot;text/javascript&quot; src=&quot;jquery/mytoolbox.js&quot;&gt;&lt;/script&gt;</strong>
&lt;script type=&quot;text/javascript&quot;&gt;
<strong>$(function () {</strong>
    <strong>$('.test').mytoolbox();</strong>
<strong>});</strong>
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>首先 HTML 中引用了 jQuery 函式庫及我們寫的 Plugin 檔案，然後我在畫面上佈置了兩個 class 為 test 的 div 元素。接著我們用以下程式碼來呼叫我們的 Plugin ：</p>
<pre><code>$(function () {
    $('.test').mytoolbox();
});</code></pre>
<p>這邊的用意就是將上面那兩個 div 套上 mytoolbox 這個 Plugin ，這樣 Plugin 就能動了，很簡單吧？</p>
<h2>加入動作</h2>
<p>當然，這個 Plugin 什麼事都還沒開始做，是個空骨架而已。現在我們要為它加血添肉，讓它動起來。</p>
<p>先簡單在 each 的 callback 裡加入一行：</p>
<pre><code>jQuery.fn.mytoolbox = function() {
    return this.each(function() {
        <strong>alert(this.id);</strong> // 加入此行
    });
};</code></pre>
<p>再重新瀏覽測試用的 HTML 檔，你會發現頁面自動跳出了兩次訊息視窗，內容分別是 test1 和 test2 ；這證明了我們的 Plugin 的確有套用在 class 為 test 的兩個 div 上面。</p>
<p>不過現在有兩個 this ，它們是一樣的東西嗎？不，因為 scope 及觸發對象的不同，它們兩個是不同的東西。在外面的 this 是一個 jQuery 物件，指向我們指定的 $('.test') 這個物件；而 each callback 裡的 this 則是 div 元素，因為 each 是個 iterator function ，因此 alert(this.id) 會執行兩次。在第一次的 this 會指向 #test1 這個 div ，第二次則指向 #test2 這個 div 。</p>
<p class="note">註：這裡我用 #test1 表示 id 為 test1 的元素。</p>
<p>現在我希望改成按下 div 元素後才會 alert 該元素的 id ，這要怎麼做呢？我們要改用 click 事件，做法如下：</p>
<pre><code>jQuery.fn.mytoolbox = function() {
    return this.each(function() {
        <strong>jQuery(this).click(function () {</strong>
            <strong>alert(this.id);</strong>
        <strong>});</strong>
    });
};</code></pre>
<p>由於 each callback 裡的 this 是 DOM 元素，所以我們要用 jQuery() 把 this 包起來，這樣才能方便指定該元素的 click 事件。現在重新瀏覽頁面，點選任何一個 div ，應該就會跳出對應的訊息視窗了。</p>
<h2>再包一層</h2>
<p>如果在 each 的 callback 裡會呼叫到多次的 jQuery 的話，一直寫 jQuery 這幾個字實在是很累人的一件事；而且 jQuery 不是可以簡寫成 $ 號嗎？不能直接用嗎？當然可以，只是這樣可能會和其他 JavaScript Library 發生衝突；所以我們要改用以下的方式來包覆我們的 Plugin ：</p>
<pre><code><strong>;(function($) {</strong>

<strong>$</strong>.fn.mytoolbox = function() {
    return this.each(function() {
        <strong>$</strong>(this).click(function () {
            alert(this.id);
        });
    });
};

<strong>})(jQuery);</strong></code></pre>
<p>JavaScript 可以直接用一組小括號 [()] 包覆一個匿名函式，然後後面再接一組小括號 [()]  表示呼叫這個匿名函式；而第二組小括號中就可以放置這個匿名函式的參數。所以在上面的程式碼中，我們把 Plugin 的程式碼用一個匿名函式包覆起來，然後參數就用我們常用的 $ 符號；接著在利用前述的原理，將 jQuery 這個類別導入給我們的 Plugin ，這樣我們就可以很快樂地在 Plugin 中使用我們熟悉的 $ 符號了。至於最前面的分號 (;) ，主要是考慮這個 Plugin 檔案會和其他 JS 檔合併壓縮而放進來的。</p>
<p class="note">註： $ 在 JavaScript 裡是合法的變數名稱。</p>
<p>後面的說明我會略過這個包覆動作，在實際檔案中請別忘了加。</p>
<h2>加入選項設定</h2>
<p>接下來我希望讓 each 的 callback 函式能讓使用者自訂，因此我需要一個讓使用者能設定的選項。就像其他的 Plugin 一樣，我們讓我們的 mytoolbox 可以接受一個 JSON 物件：</p>
<pre><code>$.fn.mytoolbox = function(<strong>settings</strong>) {

    <strong>var _defaultSettings = {</strong>
        <strong>callback: function () {</strong>
            <strong>alert(this.id);</strong>
        <strong>}</strong>
    <strong>};</strong>

    <strong>var _settings = $.extend(_defaultSettings, settings);</strong>

    return this.each(function() {
        $(this).click(<strong>_settings.callback</strong>);
    });
};</code></pre>
<p>首先我們為 Plugin 加入 settings 參數，也就是一般 Plugin 常見的設定值。然後則是 _defaultSettings ，它能幫我們在使用者沒有指定任何設定值給 settings 時，還能夠提供預設的設定值。</p>
<p>接著我用 jQuery 提供的 extend 方法，將 settings 中有設定的值覆蓋掉 _defaultSettings 所設定的預設值，再把結果存放在 _settings 這個變數中；後面我們就會用新的 _settings 變數當做我們的設定值。</p>
<p>現在我們在 _settings 中指定了一個 callback 項目 (預設是用 alert ) ，然後將它指定給 div 元素的 click 觸發器。現在我要在 HTML 頁面中更改這個事件處理器，使它不再使用 alert ，而是把結果顯示在 div#debug 裡。程式如下：</p>
<pre><code>$(function () {
    <strong>var debug = $('#debug');</strong>
    $('.test').mytoolbox(<strong>{</strong>
        <strong>callback: function () {</strong>
            <strong>debug.html(debug.html() + this.id + '&lt;br /&gt;');</strong>
        <strong>}</strong>
    <strong>}</strong>);
});</code></pre>
<p>再重新瀏覽一次頁面，看看效果是不是依照我們想像的完成呢？</p>
<h2>修改觸發事件</h2>
<p>假設現在我們不想用 click ，而是想讓滑鼠移過就觸發 callback 呢？這時就要借重 jQuery 的 bind 方法了：</p>
<pre><code>$.fn.mytoolbox = function(settings) {

    var _defaultSettings = {
        <strong>bind: 'click',</strong>
        callback: function () {
            alert(this.id);
        }
    };

    var _settings = $.extend(_defaultSettings, settings);

    return this.each(function() {
        <strong>$(this).bind(_settings.bind, _settings.callback);</strong>
    });
};</code></pre>
<p>這裡我加入一個 bind 設定項目，預設是用 click 事件觸發。回到 HTML 頁面，我們改用 mouseover 來觸發 callback ：</p>
<pre><code>$(function () {
    var debug = $('#debug');
    $('.test').mytoolbox({
        <strong>bind: 'mouseover',</strong>
        callback: function () {
            debug.html(debug.html() + this.id + '&lt;br /&gt;');
        }
    });
});</code></pre>
<p>重新瀏覽 HTML 頁面，當滑鼠移過 div 元素時，是不是會出現對應的 id 呢？</p>
<p>到這裡，相信大家都應該大致瞭解如何建立一個 jQuery Plugin 了吧？接下來，我將透過實際的例子為大家介紹更多自製 jQuery Plugin 所需要注意的地方。</p>
<p>請觀賞 <a href="http://blog.roodo.com/jaceju/archives/6034507.html">Part 2</a> 。</p>
<h2>參考網址</h2>
<ul>
<li><a href="http://www.learningjquery.com/2007/10/a-plugin-development-pattern">A Plugin Development Pattern</a> </li>
</ul>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/6016309.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/6016309.html</guid>
	<category>JavaScript</category>
	<pubDate>Tue, 13 May 2008 00:21:11 +0800</pubDate>
</item>
<item>
	<title>dean 的 IE7 Library 釋出新版</title>
	<description><![CDATA[
	完整文章連結：IE7.js version 2.0 (beta) 
這次從 0.9 直接跳到 2.0 beta ，而且拆成了 IE7.js 和 IE8.js 兩個部份。
 IE7.js 把功能只精簡到微軟正牌 IE7 有實作的部份，其他加強的部份就移到 IE8.js 上了 (因為 IE8 已經趕上 Web 標準了) 。其他修正部份如下：

The IE7 project is now hosted on googlecode (I got fed up with SourceForge).
IE7 is no longer modular. Instead I’ve merged the scripts into two: IE7.js and IE8.js
IE7.js includes only fixes that are included in the real MSIE7 browser.
All other enhancements are moved to IE8.js.
IE7 is now much smaller (11KB gzipped).
IE7 is now much faster (it uses the selector engine from base2.DOM)
There are no dependencies on other files (except blank.gif)
You can hotlink IE7/IE8.js directly from Google’s servers (usage instructions below)
The fix for base64 encoded images is no longer included

看起來不錯喔，有興趣的朋友不妨試一下。


	]]>
	</description>
	<content:encoded><![CDATA[
	<p>完整文章連結：<a href="http://dean.edwards.name/weblog/2008/01/ie7-2/">IE7.js version 2.0 (beta)</a> </p>
<p>這次從 0.9 直接跳到 2.0 beta ，而且拆成了 IE7.js 和 IE8.js 兩個部份。</p>
<p> IE7.js 把功能只精簡到微軟正牌 IE7 有實作的部份，其他加強的部份就移到 IE8.js 上了 (因為 <a href="http://blogs.msdn.com/ie/archive/2007/12/19/internet-explorer-8-and-acid2-a-milestone.aspx">IE8 已經趕上 Web 標準</a>了) 。其他修正部份如下：</p>
<ul>
<li>The IE7 project is now <a href="http://code.google.com/p/ie7-js/">hosted on googlecode</a> (I got fed up with <a href="https://sourceforge.net/">SourceForge</a>).</li>
<li>IE7 is no longer modular. Instead I’ve merged the scripts into two: IE7.js and IE8.js</li>
<li>IE7.js includes <em>only</em> fixes that are included in the real MSIE7 browser.</li>
<li>All other enhancements are moved to IE8.js.</li>
<li>IE7 is now much smaller (11KB gzipped).</li>
<li>IE7 is now much faster (it uses the selector engine from <a href="http://dean.edwards.name/weblog/2007/03/yet-another/">base2.DOM</a>)</li>
<li>There are no dependencies on other files (except <tt>blank.gif</tt>)</li>
<li>You can <a href="http://ie7-js.googlecode.com/svn/version/">hotlink</a> IE7/IE8.js directly from Google’s servers (usage instructions below)</li>
<li>The <a href="http://dean.edwards.name/weblog/2005/06/base64-ie/">fix for base64 encoded images</a> is no longer included</li>
</ul>
<p>看起來不錯喔，有興趣的朋友不妨試一下。</p>

		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/4783465.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/4783465.html</guid>
	<category>JavaScript</category>
	<pubDate>Mon, 07 Jan 2008 10:13:47 +0800</pubDate>
</item>
<item>
	<title>[JavaScript] window.onresize 連續觸發的問題</title>
	<description><![CDATA[
	今天遇到了一個怪異的問題，就是在 IE6 底下 window 的 onresize 這個事件竟然會在視窗大小沒有改變的情況下被連續觸發；試了一下 Firefox 和 IE7 都沒有這個問題，所以我便懷疑是 IE6 有實作上的錯誤。
為了查證，我 Google 了一下，找到了以下這篇文章：
IE Fires Onresize When Body Resizes
原來 IE6 會在 body 被 resize 時，同時觸發 window 的 resize 事件。
不過 body 什麼時候會被 resize 呢？通常就是利用 display 來顯示或隱藏元素的時候，例如： 
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;
 &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;Content-Type&quot;
 content=&quot;text/html; charset=utf-8&quot; /&gt;
&lt;title&gt;window.onresize&lt;/title&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
var link  = null;
var block = null;

var resizeWindow = function () {
    alert('resized');
};

window.onload = function () {
    link  = document.getElementById('link');
    block = document.getElementById('block');
    link.onmouseover = function () {
        block.style.display = 'block'
    };
    link.onmouseout  = function () {
        block.style.display = 'none'
    };
    window.onresize = resizeWindow;
};
&lt;/script&gt;
&lt;/head&gt;

&lt;body&gt;
&lt;a href=&quot;window.onresize.html&quot; id=&quot;link&quot;&gt;Link&lt;/a&gt;
&lt;div id=&quot;block&quot; style=&quot;display:none;&quot;&gt;
&lt;p&gt;Show something.&lt;/p&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
這時候當滑鼠移到 Link 上時，因為元素會有消長，所以 body 的 resize 就會被觸發 (也即 reflow 這個觀念) ，只是這時候 IE6 就會很雞婆地一起觸發 window 的 resize 事件，而且會一直連續觸發；如果這時我們在 window.onresize 有設定要處理某些東西的話 (例如上面的 resizeWindow 函式) ，就會使得真正的 mouseover 和 mouseout 事件無法正常動作。
而我會遇到這個狀況是因為我需要在 window.onresize 裡處理一些排版上的問題，也就是在視窗大小變化後，有些透過 JavaScript 來調整寬度的選單就需要重新調整。但是這時如果連續觸發了 window 的 resize 事件，就會造成整個程式執行起來頓頓的。
還好上面找到的文章提供了一個解法，那就是判斷 document.documentElement.clientHeight 是不是有被改變了。所以我只要把 resizeWindow 這個事件改成以下的樣子就可以了：
var currentClientHeight = 0;

var resizeWindow = function () {
    if (currentClientHeight != document.documentElement.clientHeight) {
        alert('resized');
    }
    currentClientHeight = document.documentElement.clientHeight;
};
雖然 window 的 resize 事件還是會被連續觸發，但是至少觸發時所需要執行的動作減少了，這樣就不會讓程式執行起來感覺頓頓的了。 

	]]>
	</description>
	<content:encoded><![CDATA[
	<p>今天遇到了一個怪異的問題，就是在 IE6 底下 window 的 onresize 這個事件竟然會在視窗大小沒有改變的情況下被連續觸發；試了一下 Firefox 和 IE7 都沒有這個問題，所以我便懷疑是 IE6 有實作上的錯誤。</p>
<p>為了查證，我 Google 了一下，找到了以下這篇文章：</p>
<p><a href="http://snook.ca/archives/javascript/ie6_fires_onresize/">IE Fires Onresize When Body Resizes</a></p>
<p>原來 IE6 會在 body 被 resize 時，同時觸發 window 的 resize 事件。</p>
<p>不過 body 什麼時候會被 resize 呢？通常就是利用 display 來顯示或隱藏元素的時候，例如： </p>
<pre><code>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;
 &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;Content-Type&quot;
 content=&quot;text/html; charset=utf-8&quot; /&gt;
&lt;title&gt;window.onresize&lt;/title&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
var link  = null;
var block = null;

var resizeWindow = function () {
    alert('resized');
};

window.onload = function () {
    link  = document.getElementById('link');
    block = document.getElementById('block');
    link.onmouseover = function () {
        block.style.display = 'block'
    };
    link.onmouseout  = function () {
        block.style.display = 'none'
    };
    window.onresize = resizeWindow;
};
&lt;/script&gt;
&lt;/head&gt;

&lt;body&gt;
&lt;a href=&quot;window.onresize.html&quot; id=&quot;link&quot;&gt;Link&lt;/a&gt;
&lt;div id=&quot;block&quot; style=&quot;display:none;&quot;&gt;
&lt;p&gt;Show something.&lt;/p&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>這時候當滑鼠移到 Link 上時，因為元素會有消長，所以 body 的 resize 就會被觸發 (也即 <a href="http://realazy.org/blog/2007/09/09/reflow/">reflow</a> 這個觀念) ，只是這時候 IE6 就會很雞婆地一起觸發 window 的 resize 事件，而且會一直連續觸發；如果這時我們在 window.onresize 有設定要處理某些東西的話 (例如上面的 resizeWindow 函式) ，就會使得真正的 mouseover 和 mouseout 事件無法正常動作。</p>
<p>而我會遇到這個狀況是因為我需要在 window.onresize 裡處理一些排版上的問題，也就是在視窗大小變化後，有些透過 JavaScript 來調整寬度的選單就需要重新調整。但是這時如果連續觸發了 window 的 resize 事件，就會造成整個程式執行起來頓頓的。</p>
<p>還好上面找到的文章提供了一個解法，那就是判斷 document.documentElement.clientHeight 是不是有被改變了。所以我只要把 resizeWindow 這個事件改成以下的樣子就可以了：</p>
<pre><code>var currentClientHeight = 0;

var resizeWindow = function () {
    if (currentClientHeight != document.documentElement.clientHeight) {
        alert('resized');
    }
    currentClientHeight = document.documentElement.clientHeight;
};</code></pre>
<p>雖然 window 的 resize 事件還是會被連續觸發，但是至少觸發時所需要執行的動作減少了，這樣就不會讓程式執行起來感覺頓頓的了。 </p>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/4203761.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/4203761.html</guid>
	<category>JavaScript</category>
	<pubDate>Fri, 28 Sep 2007 20:00:00 +0800</pubDate>
</item>
<item>
	<title>[JavaScript] jQuery UI 1.0 釋出</title>
	<description><![CDATA[
	隨著 jQuery 1.2.1 的推出，一個 Interface 的後繼者也出現了，它叫做 jQuery UI 。 
jQuery UI: Interactions and Widgets
小試了一下它的 DEMO ，還是有一些 Bug ，不過整體來說還是非常不錯。
主要有以下的功能：

Draggables
Droppables (有 Bug) 
Sortables
Selectables
Resizables
Accordion
Calendar (有 Bug) 
Dialog
Slider
Tablesorter
Tabs
Magnifier
Shadow

文件在這裡，然後應用的 DEMO 在這裡。 

	]]>
	</description>
	<content:encoded><![CDATA[
	<p>隨著 jQuery 1.2.1 的推出，一個 <a href="http://interface.eyecon.ro/">Interface</a> 的後繼者也出現了，它叫做 <a href="http://ui.jquery.com/">jQuery UI</a> 。 </p>
<p><a href="http://jquery.com/blog/2007/09/17/jquery-ui-interactions-and-widgets/">jQuery UI: Interactions and Widgets</a></p>
<p>小試了一下它的 DEMO ，還是有一些 Bug ，不過整體來說還是非常不錯。</p>
<p>主要有以下的功能：</p>
<ul>
<li><a href="http://docs.jquery.com/UI/Draggables">Draggables</a></li>
<li><a href="http://docs.jquery.com/UI/Droppables">Droppables</a> (有 Bug) </li>
<li><a href="http://docs.jquery.com/UI/Sortables">Sortables</a></li>
<li><a href="http://docs.jquery.com/UI/Selectables">Selectables</a></li>
<li><a href="http://docs.jquery.com/UI/Resizables">Resizables</a></li>
<li><a href="http://docs.jquery.com/UI/Accordion">Accordion</a></li>
<li><a href="http://docs.jquery.com/Plugins/Calendar">Calendar</a> (有 Bug) </li>
<li><a href="http://docs.jquery.com/UI/Dialog">Dialog</a></li>
<li><a href="http://docs.jquery.com/UI/Slider">Slider</a></li>
<li><a href="http://docs.jquery.com/Plugins/Tablesorter">Tablesorter</a></li>
<li><a href="http://docs.jquery.com/UI/Tabs">Tabs</a></li>
<li><a href="http://docs.jquery.com/UI/Magnifier">Magnifier</a></li>
<li><a href="http://docs.jquery.com/UI/Shadow">Shadow</a></li>
</ul>
<p>文件在<a href="http://docs.jquery.com/UI">這裡</a>，然後應用的 DEMO 在<a href="http://dev.jquery.com/view/trunk/plugins/ui/apps/gallery_advanced/">這裡</a>。 </p>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/4152721.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/4152721.html</guid>
	<category>JavaScript</category>
	<pubDate>Mon, 17 Sep 2007 17:58:53 +0800</pubDate>
</item>
<item>
	<title>[JavaScript] jQuery 1.2.1 釋出</title>
	<description><![CDATA[
	觀望得果然沒錯， jQuery 1.2.1 釋出了。
jQuery 1.2.1: Quick Fixes for 1.2
1.2.1 版解決了一些 IE 上 Ajax 的問題， 然後也把 eq() 這個方法又放了回來，免得有一堆 plugins 不能用。
看來 jQuery 1.2 這個版本大概要到 1.2.2 才會穩定，暫時我還是保留觀望的態度好了。
話說阿土伯好像很忙，還沒看到他對 jQuery 的新版本表示一下意見。 

	]]>
	</description>
	<content:encoded><![CDATA[
	<p>觀望得果然沒錯， jQuery 1.2.1 釋出了。</p>
<p><a href="http://jquery.com/blog/2007/09/16/jquery-121-quick-fixes-for-12/">jQuery 1.2.1: Quick Fixes for 1.2</a></p>
<p>1.2.1 版解決了一些 IE 上 Ajax 的<a href="http://dev.jquery.com/report/17">問題</a>， 然後也把 eq() 這個方法又放了回來，免得有一堆 plugins 不能用。</p>
<p>看來 jQuery 1.2 這個版本大概要到 1.2.2 才會穩定，暫時我還是保留觀望的態度好了。</p>
<p>話說<a href="http://racklin.blogspot.com/">阿土伯</a>好像很<a href="http://racklin.blogspot.com/2007/09/gre.html">忙</a>，還沒看到他對 jQuery 的新版本表示一下意見。 </p>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/4152073.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/4152073.html</guid>
	<category>JavaScript</category>
	<pubDate>Mon, 17 Sep 2007 14:09:41 +0800</pubDate>
</item>
<item>
	<title>[JavaScript] jQuery 1.2 釋出</title>
	<description><![CDATA[
	果然 jQuery 1.1.4 剛出沒多久， jQuery 1.2 就跑出來湊熱鬧了 
jQuery 1.2: jQuery.extend(&quot;Awesome&quot;)
主要的改變像是把 XPath 的解析方式拆成 plugin 、 Cross-Domain getScript 、  Namespaced Events 等等；不過還是等看看阿土伯的技術分析好了，我乖乖地偷學就行 XD 
註：又搶先阿土伯一步了 XD (呃... GSLin 偷跑... Orz)

	]]>
	</description>
	<content:encoded><![CDATA[
	<p>果然 jQuery 1.1.4 剛出沒多久， jQuery 1.2 就跑出來湊熱鬧了 </p>
<p><a href="http://jquery.com/blog/2007/09/10/jquery-12-jqueryextendawesome/">jQuery 1.2: jQuery.extend(&quot;Awesome&quot;)</a></p>
<p>主要的改變像是把 XPath 的解析方式拆成 plugin 、 Cross-Domain getScript 、  Namespaced Events 等等；不過還是等看看阿土伯的技術分析好了，我乖乖地偷學就行 XD </p>
<p class="note">註：又搶先<a href="http://racklin.blogspot.com/">阿土伯</a>一步了 XD (呃... GSLin <a href="http://blog.gslin.org/archives/2007/09/11/1308/">偷跑</a>... Orz)</p>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/4120969.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/4120969.html</guid>
	<category>JavaScript</category>
	<pubDate>Tue, 11 Sep 2007 14:03:23 +0800</pubDate>
</item>
<item>
	<title>[JavaScript] jQuery 推出 1.1.4 版</title>
	<description><![CDATA[
	jQuery 1.1.4: Faster, More Tests, Ready for 1.2
還沒看到阿土伯的介紹，所以我先貼一下好了。
Updated: 阿土伯也寫介紹囉~~是篇很精采的技術分析，請看 Racklin's 阿土伯程式大觀園::jQuery 1.1.4 Release 。
jQuery 推出了 1.1.4 版，速度變得更快了。如果我沒看錯的話，某些狀況有快到 16 倍之譜，不過不曉得是不是把一些功能分離出去或直接拿掉的關係。
 jQuery 也可以用以下的方式來與其他 JavaScript Library 結合： 
// With the Dojo Toolkit
dojo.jquery = jQuery.noConflict(true);
dojo.jquery("#elem div").slideDown("slow");
// or with Yahoo UI
YAHOO.query = jQuery.noConflict(true);
YAHOO.query("span.hidden").removeClass("hidden");
另外 jQuery 也多了幾個新函式，並移除幾個不常用的功能；這些我想都是因應使用者的回應，並且準備導向 1.2 版所作的決定。 
註：不過如果有 plugin 用到這些廢除功能的話就慘了，看來我得再持續關心後續的發展。
總之 jQuery 越來越令人欣賞了，不過我還是等看看 1.1.4.1 會不會馬上蹦出來好了。 

	]]>
	</description>
	<content:encoded><![CDATA[
	<p><a href="http://jquery.com/blog/2007/08/24/jquery-114-faster-more-tests-ready-for-12/">jQuery 1.1.4: Faster, More Tests, Ready for 1.2</a></p>
<p>還沒看到<a href="http://racklin.blogspot.com/">阿土伯</a>的介紹，所以我先貼一下好了。</p>
<p><strong>Updated:</strong> 阿土伯也寫介紹囉~~是篇很精采的技術分析，請看 <a href="http://racklin.blogspot.com/">Racklin's 阿土伯程式大觀園</a>::<a href="http://racklin.blogspot.com/2007/08/jquery-114-release.html">jQuery 1.1.4 Release</a> 。</p>
<p>jQuery 推出了 1.1.4 版，速度變得更快了。如果我沒看錯的話，某些狀況有快到 16 倍之譜，不過不曉得是不是把一些功能分離出去或直接拿掉的關係。</p>
<p> jQuery 也可以用以下的方式來與其他 JavaScript Library 結合： </p>
<pre><code>// With the Dojo Toolkit
dojo.jquery = jQuery.noConflict(true);
dojo.jquery("#elem div").slideDown("slow");
// or with Yahoo UI
YAHOO.query = jQuery.noConflict(true);
YAHOO.query("span.hidden").removeClass("hidden");</code></pre>
<p>另外 jQuery 也多了幾個新函式，並移除幾個不常用的功能；這些我想都是因應使用者的回應，並且準備導向 1.2 版所作的決定。 </p>
<p class="note">註：不過如果有 plugin 用到這些廢除功能的話就慘了，看來我得再持續關心後續的發展。</p>
<p>總之 jQuery 越來越令人欣賞了，不過我還是等看看 1.1.4.1 會不會馬上蹦出來好了。 </p>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/4004605.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/4004605.html</guid>
	<category>JavaScript</category>
	<pubDate>Fri, 24 Aug 2007 18:24:34 +0800</pubDate>
</item>
<item>
	<title>[轉載] 5 個加速 JavaScript 執行速度的方法</title>
	<description><![CDATA[
	5 ways to speedup javascript
5 個加速 JavaScript 執行速度的方法，節錄如下：


use a compressor (使用壓縮器，例如 JSMin ；據說對岸高手寫的 JSA 也不錯。)


minimize the number of .js files (減少 JS 檔案的引入次數，因為會引發多次的 HTTP 要求。)


use profiler and timer tools (用側錄及計時工具來分析效能，推薦使用 Firebug 。)


asynchronize your code (以非同步來執行程式碼；大意是不要直接在頁面解析時就執行程式，而是利用 setTimeout 來背景執行。) 


cache DOM variables (快取 DOM 變數；簡單來說就是把類似 document.getElementById 取到的節點放在變數裡，而不是每次都要再執行一次。) 



	]]>
	</description>
	<content:encoded><![CDATA[
	<p><a href="http://www.whenpenguinsattack.com/2007/08/20/5-ways-to-speedup-javascript/">5 ways to speedup javascript</a></p>
<p>5 個加速 JavaScript 執行速度的方法，節錄如下：</p>
<ol>
<li>
<p><strong>use a compressor</strong> (使用壓縮器，例如 <a href="http://code.google.com/p/jsmin-php/">JSMin</a> ；據說對岸高手寫的 <a href="http://jindw.spaces.live.com/blog/cns!4D0B98F5F0C51177!114.entry">JSA</a> 也不錯。)</p>
</li>
<li>
<p><strong>minimize the number of .js files</strong> (減少 JS 檔案的引入次數，因為會引發多次的 HTTP 要求。)</p>
</li>
<li>
<p><strong>use profiler and timer tools</strong> (用側錄及計時工具來分析效能，推薦使用 <a href="http://www.getfirebug.com/">Firebug</a> 。)</p>
</li>
<li>
<p><strong>asynchronize your code</strong> (以非同步來執行程式碼；大意是不要直接在頁面解析時就執行程式，而是利用 setTimeout 來背景執行。) </p>
</li>
<li>
<p><strong>cache DOM variables</strong> (快取 DOM 變數；簡單來說就是把類似 document.getElementById 取到的節點放在變數裡，而不是每次都要再執行一次。) </p>
</li>
</ol>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3980701.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3980701.html</guid>
	<category>JavaScript</category>
	<pubDate>Tue, 21 Aug 2007 23:24:02 +0800</pubDate>
</item>
<item>
	<title>[JavaScript] 相關連結</title>
	<description><![CDATA[
	JavaScript 越來越神奇了，從大家都認為只是小玩意的技術，搖身一變成為高手們競相研究的對象。
以下兩個連結就可以看出 JavaScript 真的是非常有趣的一門語言：

One-Line JavaScript Memoization
Lazy Function Definition Pattern (簡體中文版 by Realazy)

順便附上幾個 JavaScript 相關技術的文章：

A JavaScript Module Pattern
Browser Detecting (and what to do Instead)


	]]>
	</description>
	<content:encoded><![CDATA[
	<p>JavaScript 越來越神奇了，從大家都認為只是小玩意的技術，搖身一變成為高手們競相研究的對象。</p>
<p>以下兩個連結就可以看出 JavaScript 真的是非常有趣的一門語言：</p>
<ul>
<li><a href="http://osteele.com/archives/2006/04/javascript-memoization">One-Line JavaScript Memoization</a></li>
<li><a href="http://peter.michaux.ca/article/3556">Lazy Function Definition Pattern</a> (<a href="http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/">簡體中文版</a> by <a href="http://realazy.org/blog/">Realazy</a>)</li>
</ul>
<p>順便附上幾個 JavaScript 相關技術的文章：</p>
<ul>
<li><a href="http://yuiblog.com/blog/2007/06/12/module-pattern/">A JavaScript Module Pattern</a></li>
<li><a href="http://www.jibbering.com/faq/faq_notes/not_browser_detect.html">Browser Detecting (and what to do Instead)</a></li>
</ul>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3940769.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3940769.html</guid>
	<category>JavaScript</category>
	<pubDate>Thu, 16 Aug 2007 14:41:19 +0800</pubDate>
</item>
<item>
	<title>[JavaScript] 有關 jQuery</title>
	<description><![CDATA[
	steve 網友問到了 jQuery 有什麼特點，其實我才疏學淺，沒能給什麼好建議。
不過剛剛恰好看到一篇 jQuery for JavaScript programmers ，這裡推薦給對 jQuery 有興趣的朋友參考看看。
順便整理一下一些有關 jQuery 的連結：


jQuery
官方網站


Learning jQuery::What is this?
簡單的 jQuery 介紹。


jQuery API Browser (for jQuery 1.1.2) 
API 查詢，也有提供範例。


Visual jQuery (for jQuery 1.1.2)
和上面一樣也是 API 查詢，只是介面不同。


jQuery.com 1.1 - Cheat Sheet
作弊小抄....啊，不是，是速查表。不過我還是喜歡上面的 API Browser ，比 cheat sheet 方便。


不過基本上我都是看官方網站找 plugins ，然後查一下 API Browser 而已。比較深入研究的話，就要找阿土伯，他是個 JavaScript 高手。 :) 

	]]>
	</description>
	<content:encoded><![CDATA[
	<p>steve 網友問到了 jQuery 有什麼特點，其實我才疏學淺，沒能給什麼好建議。</p>
<p>不過剛剛恰好看到一篇 <a href="http://simonwillison.net/2007/Aug/15/jquery/">jQuery for JavaScript programmers</a> ，這裡推薦給對 jQuery 有興趣的朋友參考看看。</p>
<p>順便整理一下一些有關 jQuery 的連結：</p>
<ul>
<li>
<p><a href="http://jquery.com">jQuery</a></p>
<p>官方網站</p>
</li>
<li>
<p><a href="http://www.learningjquery.com/">Learning jQuery</a>::<a href="http://www.learningjquery.com/2007/08/what-is-this" rel="bookmark" title="Permanent Link: What is &lt;em&gt;this&lt;/em&gt;?">What is <em>this</em>?</a></p>
<p>簡單的 jQuery 介紹。</p>
</li>
<li>
<p><a href="http://jquery.bassistance.de/api-browser/">jQuery API Browser (for jQuery 1.1.2)</a> </p>
<p>API 查詢，也有提供範例。</p>
</li>
<li>
<p><a href="http://visualjquery.com/">Visual jQuery (for jQuery 1.1.2)</a></p>
<p>和上面一樣也是 API 查詢，只是介面不同。</p>
</li>
<li>
<p><a href="http://www.n-bp.com/jquery_cheat_sheet/v11_catalog_extra/">jQuery.com 1.1 - Cheat Sheet</a></p>
<p>作弊小抄....啊，不是，是速查表。不過我還是喜歡上面的 API Browser ，比 cheat sheet 方便。</p>
</li>
</ul>
<p>不過基本上我都是看官方網站找 plugins ，然後查一下 API Browser 而已。比較深入研究的話，就要找<a href="http://racklin.blogspot.com/">阿土伯</a>，他是個 JavaScript 高手。 :) </p>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3933923.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3933923.html</guid>
	<category>JavaScript</category>
	<pubDate>Wed, 15 Aug 2007 12:17:51 +0800</pubDate>
</item>
<item>
	<title>jQuery 1.1.3 釋出，速度快 8 倍</title>
	<description><![CDATA[
	jQuery 1.1.3 釋出了，主要特色如下：


速度比舊版快 8 倍！ 


Seletor 語法支援 Unicode 。 (範例還用台北耶~) 


加強的動畫效果。


其他沒空介紹的特色。


更詳細的介紹請參考： jQuery 1.1.3: 800%+ Faster, still 20KB
總而言之，沒人敢再笑 jQuery 慢了吧？
註：其實做 JavaScript Framework 不就是這樣嗎？就好像跑步游泳，你做了什麼，別人就會跟著加什麼。更何況這些技術都是公開的，只要能讓我們開發更方便，就別爭那麼多了。 

	]]>
	</description>
	<content:encoded><![CDATA[
	<p>jQuery 1.1.3 釋出了，主要特色如下：</p>
<ul>
<li>
<p><strong>速度比舊版快 8 倍！ </strong></p>
</li>
<li>
<p>Seletor 語法支援 Unicode 。 (範例還用台北耶~) </p>
</li>
<li>
<p>加強的動畫效果。</p>
</li>
<li>
<p>其他沒空介紹的特色。</p>
</li>
</ul>
<p>更詳細的介紹請參考： <a href="http://jquery.com/blog/2007/07/01/jquery-113-800-faster-still-20kb/">jQuery 1.1.3: 800%+ Faster, still 20KB</a></p>
<p>總而言之，沒人敢再笑 jQuery 慢了吧？</p>
<p class="note">註：其實做 JavaScript Framework 不就是這樣嗎？就好像跑步游泳，你做了什麼，別人就會跟著加什麼。更何況這些技術都是公開的，只要能讓我們開發更方便，就別爭那麼多了。 </p>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3565129.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3565129.html</guid>
	<category>JavaScript</category>
	<pubDate>Mon, 02 Jul 2007 11:54:28 +0800</pubDate>
</item>
<item>
	<title>Rails 有可能要移植到 JavaScript 上</title>
	<description><![CDATA[
	Rails 有可能要移植到 JavaScript 上了...
請看：

Stevey's Blog Rants::Rhino on Rails
純月部落::Steve Yegge 將 Rails 移植到 Javascript/Rhino


为了提升google的开发效率，Steve努力尝试说服公司采纳Rails（包括Ruyb）作为开发工具，但是google不予采纳(google不想再增加支持的语言的数量)。Steve决定把Rails移植到JavaScript上去。这意味着一个google有可能在未来开源一个新的项目Rhino on Rails。
限制语言的数量将使得开发人员对代码的贡献度更大，他们无需担心成为不熟悉的语法的牺牲。
每一个公司正式支持的语言都是有成本的：基础架构的支持，文档，培训，代码冗余还有其它因素。虽然编程语言的核心语法都是大同小异，但是剩下的各自独特的语法就难以辨认，尤其是没有明确标准的动态语言，例如Perl,Ptthon,Ruby。Google非常谨慎的保持使用语言的数量。这样就可以构建大量对所用语言非常熟悉的专家。goole目前只使用C++,Java,Python,javascript作为正式的产品开发语言。

註：上面引述裡有錯字，不過原文照錄。
工作太忙，也沒什麼感想，暫時記下。 

	]]>
	</description>
	<content:encoded><![CDATA[
	<p>Rails 有可能要移植到 JavaScript 上了...</p>
<p>請看：</p>
<ul>
<li><a href="http://steve-yegge.blogspot.com/2007/06/rhino-on-rails.html">Stevey's Blog Rants::Rhino on Rails</a></li>
<li><a href="http://blog.csdn.net/danny_xcz/archive/2007/06/28/1669708.aspx">純月部落::Steve Yegge 將 Rails 移植到 Javascript/Rhino</a></li>
</ul>
<blockquote>
<p>为了提升google的开发效率，Steve努力尝试说服公司采纳Rails（包括Ruyb）作为开发工具，但是google不予采纳(google不想再增加支持的语言的数量)。Steve决定把Rails移植到JavaScript上去。这意味着一个google有可能在未来开源一个新的项目Rhino on Rails。</p>
<p>限制语言的数量将使得开发人员对代码的贡献度更大，他们无需担心成为不熟悉的语法的牺牲。</p>
<p>每一个公司正式支持的语言都是有成本的：基础架构的支持，文档，培训，代码冗余还有其它因素。虽然编程语言的核心语法都是大同小异，但是剩下的各自独特的语法就难以辨认，尤其是没有明确标准的动态语言，例如Perl,Ptthon,Ruby。Google非常谨慎的保持使用语言的数量。这样就可以构建大量对所用语言非常熟悉的专家。goole目前只使用C++,Java,Python,javascript作为正式的产品开发语言。</p>
</blockquote>
<p class="note">註：上面引述裡有錯字，不過原文照錄。</p>
<p>工作太忙，也沒什麼感想，暫時記下。 </p>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3547999.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3547999.html</guid>
	<category>JavaScript</category>
	<pubDate>Thu, 28 Jun 2007 19:52:02 +0800</pubDate>
</item>
<item>
	<title>Web HTML Editor</title>
	<description><![CDATA[
	以下的跨瀏覽器線上所見即所得 HTML 編輯器，都能產生 XHTML 格式的原始碼。

Cross-Browser Rich Text Editor (RTE)
Xinha
TinyMCE
FCKEditor

我個人偏好 TinyMCE ，當然其他的也不錯。
	]]>
	</description>
	<content:encoded><![CDATA[
	<p>以下的跨瀏覽器線上所見即所得 HTML 編輯器，都能產生 XHTML 格式的原始碼。</p>
<ul>
<li><a href="http://www.kevinroth.com/rte/" target="_blank">Cross-Browser Rich Text Editor (RTE)</a></li>
<li><a href="http://xinha.python-hosting.com/" target="_blank">Xinha</a></li>
<li><a href="http://tinymce.moxiecode.com/" target="_blank">TinyMCE</a></li>
<li><a href="http://www.fckeditor.net/" target="_blank">FCKEditor</a></li>
</ul>
<p>我個人偏好 TinyMCE ，當然其他的也不錯。</p>		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3344455.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3344455.html</guid>
	<category>JavaScript</category>
	<pubDate>Fri, 25 May 2007 10:36:32 +0800</pubDate>
</item>
<item>
	<title>JavaScript 小陷阱 (8) - TinyMCE 的處理</title>
	<description><![CDATA[
	這兩天在使用 TinyMCE (版本 2.x) 上遇到了幾個小問題，這邊記一下以供備忘。
jQuery Form (with AJAX) and TinyMCE
目前在頁面上如果有表單要採用 AJAX 送出資料時，我採用的是 jQuery 的 Form plugin (with AJAX) 這個官方 plugin 。
Form plugin 使用 AJAX 來 Submit 的用法如下： 
$('myForm').submit(function () {
    $(this).ajaxSubmit();
    return false; // 這行很重要
});
可是當表單中有 TinyMCE 時，我發現接收的 PHP 程式一直收不到 TinyMCE 所轉換出來的 textarea 內容。
大致追了一下 TinyMCE 的原始碼，發現它其實先置換 form 的 submit 方法，在 submit 前先把 iframe 的內容複製到 textarea 中：
tinyMCE.formSubmit(this, true);
而 formSubmit 方法的第二個參數是指要不要呼叫原來的 submit 。瞭解這個關係以後，我就把原來的 submit 改造了一下：
$('myForm').submit(function () {
    // 讓 TinyMCE 和與 Form plugin 一起運作的關鍵
    tinyMCE.formSubmit(this, false);
    $(this).ajaxSubmit();
    return false;
});
我先透過 TinyMCE 的 formSubmit 把值複製到 textarea 裡，不過不直接 submit ，而是改由後面的 ajaxSubmit 來完成送出表單的工作。
案例一結束。 
Dynamic Textarea Content with TinyMCE
有時候我會需要在前端動態更新 Textarea 的內容，在 jQuery 下有個簡單的方法：
$('textarea.mceEditor').val('&lt;p&gt;Updated html content.&lt;/p&gt;');
這樣就能對 class 為 mceEditor 的 textarea 做內容的更新；不過很可惜，這個更新並不會立刻反應到 TinyMCE 的介面上。
怎麼辦呢？還好 TinyMCE 有提供 updateContent 這個方法，我只要在更新完 textarea 的內容後加上：
// 每個有用到 TinyMCE 的 textarea 都要更新
$('textarea.mceEditor').each(updateTinyMCE);

var updateTinyMCE = function () {
    // 注意，因為 TinyMCE 一定要使用 id 
    // 所以 textarea 一定要設定 id 屬性
    tinyMCE.updateContent(this.id);
};
這樣就能結束案例二了。
註：以上只是概念程式，實務上要配合現有的架構做相關的調整。

	]]>
	</description>
	<content:encoded><![CDATA[
	<p>這兩天在使用 TinyMCE (版本 2.x) 上遇到了幾個小問題，這邊記一下以供備忘。</p>
<h2>jQuery Form (with AJAX) and TinyMCE</h2>
<p>目前在頁面上如果有表單要採用 AJAX 送出資料時，我採用的是 jQuery 的 <a href="http://www.malsup.com/jquery/form/">Form plugin (with AJAX)</a> 這個官方 plugin 。</p>
<p>Form plugin 使用 AJAX 來 Submit 的用法如下： </p>
<pre><code>$('myForm').submit(function () {
    $(this).ajaxSubmit();
    return false; // 這行很重要
});</code></pre>
<p>可是當表單中有 TinyMCE 時，我發現接收的 PHP 程式一直收不到 TinyMCE 所轉換出來的 textarea 內容。</p>
<p>大致追了一下 TinyMCE 的原始碼，發現它其實先置換 form 的 submit 方法，在 submit 前先把 iframe 的內容複製到 textarea 中：</p>
<pre><code>tinyMCE.formSubmit(this, true);</code></pre>
<p>而 formSubmit 方法的第二個參數是指要不要呼叫原來的 submit 。瞭解這個關係以後，我就把原來的 submit 改造了一下：</p>
<pre><code>$('myForm').submit(function () {
    // 讓 TinyMCE 和與 Form plugin 一起運作的關鍵
    <strong>tinyMCE.formSubmit(this, false);</strong>
    $(this).ajaxSubmit();
    return false;
});</code></pre>
<p>我先透過 TinyMCE 的 formSubmit 把值複製到 textarea 裡，不過不直接 submit ，而是改由後面的 ajaxSubmit 來完成送出表單的工作。</p>
<p>案例一結束。 </p>
<h2>Dynamic Textarea Content with TinyMCE</h2>
<p>有時候我會需要在前端動態更新 Textarea 的內容，在 jQuery 下有個簡單的方法：</p>
<pre><code>$('textarea.mceEditor').val('&lt;p&gt;Updated html content.&lt;/p&gt;');</code></pre>
<p>這樣就能對 class 為 mceEditor 的 textarea 做內容的更新；不過很可惜，這個更新並不會立刻反應到 TinyMCE 的介面上。</p>
<p>怎麼辦呢？還好 TinyMCE 有提供 updateContent 這個方法，我只要在更新完 textarea 的內容後加上：</p>
<pre><code>// 每個有用到 TinyMCE 的 textarea 都要更新
$('textarea.mceEditor').<strong>each</strong>(updateTinyMCE);

var updateTinyMCE = function () {
    // 注意，因為 TinyMCE 一定要使用 id 
    // 所以 textarea 一定要設定 id 屬性
    <strong>tinyMCE.updateContent(this.id);</strong>
};</code></pre>
<p>這樣就能結束案例二了。</p>
<p class="note">註：以上只是概念程式，實務上要配合現有的架構做相關的調整。</p>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3274703.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3274703.html</guid>
	<category>JavaScript</category>
	<pubDate>Sat, 19 May 2007 12:55:56 +0800</pubDate>
</item>
<item>
	<title>簡介 window.onBeforeUnload 事件</title>
	<description><![CDATA[
	在 Gmail 中如果採用另開視窗模式 () 撰寫信件時，在隨意填寫一些文字後按下視窗右上角的關閉按鈕，會先出現以下警告視窗：
您的郵件尚未寄出，
您要捨棄此郵件嗎？
然後按下「取消」後又會出現： 
你確定要離開此頁面？
按一下「取消」停留在此頁。
按「確定」繼續，或「取消」以停留在此頁面。
這是利用 onBeforeUnload 事件來完成的，目的在避免使用者操作錯誤時，使得他所輸入的文字付諸流水。
以下是模擬的方式：
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;
 &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
&lt;title&gt;TEST&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
window.onbeforeunload = function () {
    if (!confirm('您的郵件尚未寄出，\n您要捨棄此郵件嗎？')) {
        return '按一下「取消」停留在此頁。';
    }
}
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
目前只有 Firefox 和 IE 支援 onBeforeUnload 事件， Opera 到 9.20 版為止都尚無支援。觸發的時機如下：

關閉瀏覽器視窗。
通過網址列或書籤 (我的最愛) 導向其他頁面。
點選上一頁、下一頁，重新整理，首頁等其中一個功能。
點選一個前往其他頁面的 URL 連結。
觸發或呼叫以下任意一個事件：

onclick
document.write()
document.open()
document.close()
window.close()
window.navigate()
window.NavigateAndFind()
location.replace()
location.reload()
form.submit()


利用 window.open() 打開一個頁面，並把本頁的 window 的名字傳給要打開的頁面。
重新賦予 location.href 的值。
透過 input type=&quot;submit&quot; 按鈕提交一個具有指定 action 的表單的時候。

註：以上改自陳澤|SurfChen::onbeforeunload 事件。
如果是使用 IE7s ，那麼在按下 Tab 的 x 鍵時，有可能不會觸發 onBeforeUnload 事件。 
參考文章
更詳細的用法可參考以下網址：

洋蔥圈::如何在用戶關掉 web 瀏覽器窗口前，進行相應的動作
DHTML Lab::The IE onBeforeUnload Event Handler
陳澤|SurfChen::onbeforeunload 事件
4GuysFromRolla.com::Prompting a User to Save When Leaving a Page 

謝謝收看。
	]]>
	</description>
	<content:encoded><![CDATA[
	<p>在 Gmail 中如果採用另開視窗模式 (<img src="http://mail.google.com/mail/images/tearoff_icon.gif" alt="另開視窗" width="16" height="16" />) 撰寫信件時，在隨意填寫一些文字後按下視窗右上角的關閉按鈕，會先出現以下警告視窗：</p>
<pre><code>您的郵件尚未寄出，
您要捨棄此郵件嗎？</code></pre>
<p>然後按下「取消」後又會出現： </p>
<pre><code>你確定要離開此頁面？
按一下「取消」停留在此頁。
按「確定」繼續，或「取消」以停留在此頁面。</code></pre>
<p>這是利用 onBeforeUnload 事件來完成的，目的在避免使用者操作錯誤時，使得他所輸入的文字付諸流水。</p>
<p>以下是模擬的方式：</p>
<pre><code>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;
 &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
&lt;title&gt;TEST&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
window.onbeforeunload = function () {
    if (!confirm('您的郵件尚未寄出，\n您要捨棄此郵件嗎？')) {
        return '按一下「取消」停留在此頁。';
    }
}
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>目前只有 Firefox 和 IE 支援 onBeforeUnload 事件， Opera 到 9.20 版為止都尚無支援。觸發的時機如下：</p>
<ul>
<li>關閉瀏覽器視窗。</li>
<li>通過網址列或書籤 (我的最愛) 導向其他頁面。</li>
<li>點選上一頁、下一頁，重新整理，首頁等其中一個功能。</li>
<li>點選一個前往其他頁面的 URL 連結。</li>
<li>觸發或呼叫以下任意一個事件：
<ul>
<li>onclick</li>
<li>document.write()</li>
<li>document.open()</li>
<li>document.close()</li>
<li>window.close()</li>
<li>window.navigate()</li>
<li>window.NavigateAndFind()</li>
<li>location.replace()</li>
<li>location.reload()</li>
<li>form.submit()</li>
</ul>
</li>
<li>利用 window.open() 打開一個頁面，並把本頁的 window 的名字傳給要打開的頁面。</li>
<li>重新賦予 location.href 的值。</li>
<li>透過 input type=&quot;submit&quot; 按鈕提交一個具有指定 action 的表單的時候。</li>
</ul>
<p class="note">註：以上改自<a href="http://www.surfchen.org/?p=54">陳澤|SurfChen::onbeforeunload 事件</a>。</p>
<p>如果是使用 <a href="http://tredosoft.com/IE7_standalone">IE7s</a> ，那麼在按下 Tab 的 x 鍵時，有可能不會觸發 onBeforeUnload 事件。 </p>
<h2>參考文章</h2>
<p>更詳細的用法可參考以下網址：</p>
<ul>
<li><a href="http://www.i-boy.net/boynet/content/view/1296/37/">洋蔥圈::如何在用戶關掉 web 瀏覽器窗口前，進行相應的動作</a></li>
<li><a href="http://www.webreference.com/dhtml/diner/beforeunload/bunload2.html">DHTML Lab::The IE onBeforeUnload Event Handler</a></li>
<li><a href="http://www.surfchen.org/?p=54">陳澤|SurfChen::onbeforeunload 事件</a></li>
<li><a href="http://www.4guysfromrolla.com/webtech/100604-1.shtml">4GuysFromRolla.com::Prompting a User to Save When Leaving a Page</a> </li>
</ul>
<p>謝謝收看。</p>		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3117129.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3117129.html</guid>
	<category>JavaScript</category>
	<pubDate>Thu, 03 May 2007 16:14:33 +0800</pubDate>
</item>
<item>
	<title>JavaScript 小陷阱 (7) - IE 在處理 nodeValue 上與其他瀏覽器的差異</title>
	<description><![CDATA[
	這兩天在玩 jQuery 的 jEditable 時，發現一個 IE 一個很怪異的問題，讓我傷腦筋了一陣子。
在處理 IE 上 TD 標籤的 nodeValue 時，它顯示出來的格式竟然與其他瀏覽器不一樣。這實在是令人費解，不論我怎麼修改 jEditable ，這個問題依舊是沒有漂亮的解法。後來 Neo 老大建議我試試 TEXTAREA 及 PRE 標籤時，我才發現 IE 在處理 nodeValue 及 innerHTML 上和其他家瀏覽器有不同的作法。 

	]]>
	</description>
	<content:encoded><![CDATA[
	<p>這兩天在玩 <a href="http://jquery.com/">jQuery</a> 的 <a href="http://www.appelsiini.net/~tuupola/javascript/jEditable/">jEditable</a> 時，發現一個 IE 一個很怪異的問題，讓我傷腦筋了一陣子。</p>
<p>在處理 IE 上 TD 標籤的 nodeValue 時，它顯示出來的格式竟然與其他瀏覽器不一樣。這實在是令人費解，不論我怎麼修改 jEditable ，這個問題依舊是沒有漂亮的解法。後來 Neo 老大建議我試試 TEXTAREA 及 PRE 標籤時，我才發現 IE 在處理 nodeValue 及 innerHTML 上和其他家瀏覽器有不同的作法。 </p>
		<a href="http://blog.roodo.com/jaceju/archives/3030309.html">(繼續閱讀...)</a>;
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3030309.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3030309.html</guid>
	<category>JavaScript</category>
	<pubDate>Fri, 20 Apr 2007 11:54:58 +0800</pubDate>
</item>
<item>
	<title>JavaScript 小陷阱 (6) - JSON 在瀏覽器上的差異</title>
	<description><![CDATA[
	Neo 老大告知我有個後台的 JS Calendar 在 IE 上無法開啟，我查了一下，發現是 IE 解釋 JSON 的關係。 
我所寫的 JSON 格式的物件大致如下： 
var options = {
    a: 1,
    b: 2,
    c: 3,
};
注意 c: 3 後面有個逗號，這樣的物件會被 Firefox 所接受；而最後一個逗號後面的元素，會被 Firefox 視為 null 。 
註：這是一種便捷寫法，方便我們可以將這些物件成員在程式碼中做搬移的動作；在 PHP 陣列和 CSS 屬性也有類似的寫法。 
不過這樣的寫法在 IE 和 Opera 上就會有語法錯誤的問題了，因為正式的 JSON 規範裡並不能讓我們使用便捷語法。正確的格式應該不可以有最後一個逗號：
var options = {
    a: 1,
    b: 2,
    c: 3
};
所以撰寫 JSON 格式的物件時，還是要小心不要掉入這種陷阱裡。 

	]]>
	</description>
	<content:encoded><![CDATA[
	<p>Neo 老大告知我有個後台的 <a href="http://www.dynarch.com/projects/calendar/">JS Calendar</a> 在 IE 上無法開啟，我查了一下，發現是 IE 解釋 JSON 的關係。 </p>
<p>我所寫的 JSON 格式的<a href="http://blog.roodo.com/jaceju/archives/214716.html">物件</a>大致如下： </p>
<pre><code>var options = {
    a: 1,
    b: 2,
    c: 3<strong style="color: #F00;">,</strong>
};</code></pre>
<p>注意 c: 3 後面有個逗號，這樣的物件會被 Firefox 所接受；而最後一個逗號後面的元素，會被 Firefox 視為 null 。 </p>
<p class="note">註：這是一種便捷寫法，方便我們可以將這些物件成員在程式碼中做搬移的動作；在 PHP 陣列和 CSS 屬性也有類似的寫法。 </p>
<p>不過這樣的寫法在 IE 和 Opera 上就會有語法錯誤的問題了，因為正式的 JSON <a href="http://www.json.org/">規範</a>裡並不能讓我們使用便捷語法。正確的格式應該不可以有最後一個逗號：</p>
<pre><code>var options = {
    a: 1,
    b: 2,
    c: 3
};</code></pre>
<p>所以撰寫 JSON 格式的物件時，還是要小心不要掉入這種陷阱裡。 </p>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3026627.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3026627.html</guid>
	<category>JavaScript</category>
	<pubDate>Thu, 19 Apr 2007 11:47:49 +0800</pubDate>
</item>
<item>
	<title>一個各家瀏覽器都可接受的事件處理器簡易寫法</title>
	<description><![CDATA[
	如果臨時想讓各家瀏覽器都能處理 DOM 事件，又不想寫太多跨瀏覽器事件處理程式或使用額外的 JS 框架時，以下的程式碼可以參考看看。
註：這個方法是為了某些簡單的活動頁寫的，我想如果要做較為複雜的效果時，還是使用別人已經包裝好的函式庫比較好。
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;
 &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
&lt;title&gt;Event Testing&lt;/title&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
&lt;!-- &lt;![CDATA[
function someHandler(e, t, arg1, arg2) {
    var event_info = document.getElementById('event_info');
    var dom_info = document.getElementById('dom_info');
    var params = document.getElementById('params');
    
    event_info.innerHTML = '';
    for (var n in e) {
        event_info.innerHTML += '&lt;p&gt;&lt;strong&gt;' + n +
                                ':&lt;' + '/strong&gt; ' + e[n] + '&lt;' + '/p&gt;';
    }

    dom_info.innerHTML = '';
        for (var n in t) {
                dom_info.innerHTML += '&lt;p&gt;&lt;strong&gt;' + n +
                                      ':&lt;' + '/strong&gt; ' + t[n] + '&lt;' + '/p&gt;';    }
    params.innerHTML = '';
    params.innerHTML += '&lt;p&gt;&lt;strong&gt;arg1:&lt;' +
                        '/strong&gt; ' + arg1 + '&lt;' + '/p&gt;';
    params.innerHTML += '&lt;p&gt;&lt;strong&gt;arg2:&lt;' +
                        '/strong&gt; ' + arg2 + '&lt;' + '/p&gt;';
}
// ]]&gt; --&gt;
&lt;/script&gt;
&lt;/head&gt;

&lt;body&gt;
&lt;a href=&quot;#&quot; onclick=&quot;someHandler(event, this, 'param1', 'param2');
 return false;&quot;&gt;Show the info by eventhanlder.&lt;/a&gt;
&lt;h2&gt;Info of Event Object&lt;/h2&gt;
&lt;div id=&quot;event_info&quot;&gt;&lt;/div&gt;
&lt;h2&gt;The Params&lt;/h2&gt;
&lt;div id=&quot;params&quot;&gt;&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
主要的原理在於 HTML Tag 中 onxxxx 的屬性可以接受 event 這個關鍵字，而它就是瀏覽器的 Event 物件。所以我們就可以將 event 當做參數，傳給相關的 Event Handler 。
另外這裡也利用 this 讓 Event Handler 可以知道是哪個 DOM 節點呼叫了它。 
目前 W3C 標準與各家瀏覽器在 Event 物件上共同有的屬性如下：

altKey (是否按下 alt 鍵) 
button (滑鼠的按鍵) 
clientX (在瀏覽器可視範圍中對應的 X 軸) 
clientY (在瀏覽器可視範圍中對應的 Y 軸) 
ctrlKey (是否按下 ctrl 鍵) 
screenX (在螢幕上對應的 X 軸) 
screenY (在螢幕上對應的 Y 軸) 
shiftKey (是否按下 shift 鍵) 
type (事件類型) 

屬性的說明請參考 W3Schools::HTML DOM Event Object 。 
	]]>
	</description>
	<content:encoded><![CDATA[
	<p>如果臨時想讓各家瀏覽器都能處理 DOM 事件，又不想寫太多跨瀏覽器事件處理程式或使用額外的 JS 框架時，以下的程式碼可以參考看看。</p>
<p class="note">註：這個方法是為了某些簡單的活動頁寫的，我想如果要做較為複雜的效果時，還是使用別人已經包裝好的函式庫比較好。</p>
<pre><code>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;
 &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
&lt;title&gt;Event Testing&lt;/title&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
&lt;!-- &lt;![CDATA[
function someHandler(e, t, arg1, arg2) {
    var event_info = document.getElementById('event_info');
    var dom_info = document.getElementById('dom_info');
    var params = document.getElementById('params');
    
    event_info.innerHTML = '';
    for (var n in e) {
        event_info.innerHTML += '&lt;p&gt;&lt;strong&gt;' + n +
                                ':&lt;' + '/strong&gt; ' + e[n] + '&lt;' + '/p&gt;';
    }

    dom_info.innerHTML = '';
        for (var n in t) {
                dom_info.innerHTML += '&lt;p&gt;&lt;strong&gt;' + n +
                                      ':&lt;' + '/strong&gt; ' + t[n] + '&lt;' + '/p&gt;';<br />    }<br />
    params.innerHTML = '';
    params.innerHTML += '&lt;p&gt;&lt;strong&gt;arg1:&lt;' +
                        '/strong&gt; ' + arg1 + '&lt;' + '/p&gt;';
    params.innerHTML += '&lt;p&gt;&lt;strong&gt;arg2:&lt;' +
                        '/strong&gt; ' + arg2 + '&lt;' + '/p&gt;';
}
// ]]&gt; --&gt;
&lt;/script&gt;
&lt;/head&gt;

&lt;body&gt;
&lt;a href=&quot;#&quot; onclick=&quot;someHandler(event, this, 'param1', 'param2');
 return false;&quot;&gt;Show the info by eventhanlder.&lt;/a&gt;
&lt;h2&gt;Info of Event Object&lt;/h2&gt;
&lt;div id=&quot;event_info&quot;&gt;&lt;/div&gt;
&lt;h2&gt;The Params&lt;/h2&gt;
&lt;div id=&quot;params&quot;&gt;&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>主要的原理在於 HTML Tag 中 onxxxx 的屬性可以接受 event 這個關鍵字，而它就是瀏覽器的 Event 物件。所以我們就可以將 event 當做參數，傳給相關的 Event Handler 。</p>
<p>另外這裡也利用 this 讓 Event Handler 可以知道是哪個 DOM 節點呼叫了它。 </p>
<p>目前 W3C 標準與各家瀏覽器在 Event 物件上共同有的屬性如下：</p>
<ul>
<li><a href="http://www.w3schools.com/htmldom/event_altkey.asp">altKey</a> (是否按下 alt 鍵) </li>
<li><a href="http://www.w3schools.com/htmldom/event_button.asp">button</a> (滑鼠的按鍵) </li>
<li><a href="http://www.w3schools.com/htmldom/event_clientx.asp">clientX</a> (在瀏覽器可視範圍中對應的 X 軸) </li>
<li><a href="http://www.w3schools.com/htmldom/event_clienty.asp">clientY</a> (在瀏覽器可視範圍中對應的 Y 軸) </li>
<li><a href="http://www.w3schools.com/htmldom/event_ctrlkey.asp">ctrlKey</a> (是否按下 ctrl 鍵) </li>
<li><a href="http://www.w3schools.com/htmldom/event_screenx.asp">screenX</a> (在螢幕上對應的 X 軸) </li>
<li><a href="http://www.w3schools.com/htmldom/event_screeny.asp">screenY</a> (在螢幕上對應的 Y 軸) </li>
<li><a href="http://www.w3schools.com/htmldom/event_shiftkey.asp">shiftKey</a> (是否按下 shift 鍵) </li>
<li><a href="http://www.w3schools.com/htmldom/event_type.asp">type</a> (事件類型) </li>
</ul>
<p>屬性的說明請參考 <a href="http://www.w3schools.com/htmldom/dom_obj_event.asp">W3Schools::HTML DOM Event Object</a> 。 </p>		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2909983.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2909983.html</guid>
	<category>JavaScript</category>
	<pubDate>Sun, 25 Mar 2007 23:50:32 +0800</pubDate>
</item>
<item>
	<title>jQWebExt - jQuery 的簡易 MVC 框架</title>
	<description><![CDATA[
	jQWebExt 這個框架是在阿土伯那裡看到的，是阿土伯眾多 Open Source 專案裡的其中之一。阿土伯是網路界一個很強的 JavaScript 高手，他用 JavaScript 寫了很多有趣的應用，像是「HEMiDEMi JSONP - 誰收藏/迴響討論本文」。
jQWebExt 目前主要有以下兩個函式可用：

register: 用來將 Javascript Function 或 Extension 註冊進 jQWebExt 中，它會在 DOM ready 時呼叫您註冊的 Function , 並把設定 Options 傳給您。
require: 用來動態載入 third-party 的 javascript .js 檔案，由寫作 Extension 的您來呼叫，網頁設計人員不用去瞭解什麼 javascript 互相關聯要引用載入。

目前的應用有 ZebraTableExtension  (DEMO) 和 jQueryTabsExtension (DEMO) 。
	]]>
	</description>
	<content:encoded><![CDATA[
	<p><a href="http://racklin.blogspot.com/2007/03/jqwebext-jquery-simple-mvc-and-plugins.html">jQWebExt</a> 這個框架是在<a href="http://racklin.blogspot.com/">阿土伯</a>那裡看到的，是阿土伯眾多 Open Source 專案裡的其中之一。阿土伯是網路界一個很強的 JavaScript 高手，他用 JavaScript 寫了很多有趣的應用，像是「<a href="http://racklin.blogspot.com/2007/03/hemidemi-jsonp.html">HEMiDEMi JSONP - 誰收藏/迴響討論本文</a>」。</p>
<p>jQWebExt 目前主要有以下兩個函式可用：</p>
<ul>
<li>register: 用來將 Javascript Function 或 Extension 註冊進 jQWebExt 中，它會在 DOM ready 時呼叫您註冊的 Function , 並把設定 Options 傳給您。</li>
<li>require: 用來動態載入 third-party 的 javascript .js 檔案，由寫作 Extension 的您來呼叫，網頁設計人員不用去瞭解什麼 javascript 互相關聯要引用載入。</li>
</ul>
<p>目前的應用有 <a href="http://code.google.com/p/jqwebext/wiki/ZebraTableExtension">ZebraTableExtension</a>  (<a href="http://jqwebext.googlepages.com/test-zebra.html">DEMO</a>) 和 <a href="http://code.google.com/p/jqwebext/wiki/jQueryTabsExtension">jQueryTabsExtension</a> (<a href="http://jqwebext.googlepages.com/test-tabs.html">DEMO</a>) 。</p>		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2820001.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2820001.html</guid>
	<category>JavaScript</category>
	<pubDate>Thu, 08 Mar 2007 09:51:34 +0800</pubDate>
</item>
<item>
	<title>JavaScript 小陷阱 (5) - window.onload()</title>
	<description><![CDATA[
	我常會在頁面載入完成時，利用 window.load 來執行一些動作。基本的方式如下：

window.onload = function ()
{
  // Do something...
}
特別注意一點：如果直接把新動作附在 window.onload 的話，是會把前一個 window.onload 的動作給蓋掉的。
不過如果現在有兩個動作都需要用到 window.onload ，而且其中一個我不想改動時該怎麼辦呢？ (例如是第三方函式庫裡的程式) 

	]]>
	</description>
	<content:encoded><![CDATA[
	<p>我常會在頁面載入完成時，利用 window.load 來執行一些動作。基本的方式如下：</p>
<pre><code>
window.onload = function ()
{
  <strong>// Do something...</strong>
}</code></pre>
<p>特別注意一點：<strong>如果直接把新動作附在 window.onload 的話，是會把前一個 window.onload 的動作給蓋掉的。</strong></p>
<p>不過如果現在有兩個動作都需要用到 window.onload ，而且其中一個我不想改動時該怎麼辦呢？ (例如是第三方函式庫裡的程式) </p>
		<a href="http://blog.roodo.com/jaceju/archives/2808099.html">(繼續閱讀...)</a>;
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2808099.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2808099.html</guid>
	<category>JavaScript</category>
	<pubDate>Mon, 05 Mar 2007 18:16:28 +0800</pubDate>
</item>
<item>
	<title>我所關注的兩個 JS 框架及其應用</title>
	<description><![CDATA[
	列表
以下列出我目前所關注的兩個 JS 框架，在直欄的部份是我所知道屬於它們的延伸與應用。



主框架
Prototype
jQuery


動畫特效
script.aculo.us
Interface


燈箱效果
Lightbox JS
Lightbox Gone Wild!
ThickBox
LITBox


延伸框架
Rico
moo.fx
jQWebExt by 阿土伯


其他
&nbsp;
Other Plugins



待補... (歡迎大家補充) 
我的心得
之前在「 prototype.js 讀取陣列的方式」裡簡單介紹了 Prototype 的用途，前陣子它也因為 Ruby on Rails 推出 1.2 版而順改將版本更新到 1.5 。不過新的 Prototype 效能似乎還是有點點差，我在執行 script.aculo.us 的範例時感覺上一開始還是會頓頓的 (而且還是在本機上測的，另外還有官方的範例也差不多) 。
這時我看到另一個 JS 框架 jQuery 也推出 1.1.2 ，便拿來試用看看。在 jQuery 上對應 script.aculo.us 的動畫特效函式庫稱為 Interface ，它的動畫範例幾乎和 script.aculo.us 差不多了。而且直接在官方網站測試時，它的效果感覺就非常順暢。
不過因為這兩個框架的設計理念是有差別，而且 JS 技術不斷推陳出新的狀況下，也許它們都還有很大的進步空間。現階段我想我會持續關注它們，並且在一些專案中使用。 
設計理念
以下文章值得參考，它們在探討兩個框架設計的理念： 


Why jQuery&#39;s Philosophy is Better


jQuery: (Mis)leading the Pack



	]]>
	</description>
	<content:encoded><![CDATA[
	<h2>列表</h2>
<p>以下列出我目前所關注的兩個 JS 框架，在直欄的部份是我所知道屬於它們的延伸與應用。</p>
<table width="400" border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse;">
<tbody>
<tr>
<td width="20%" style="background-color: #EEE;">主框架</td>
<td width="40%"><a href="http://www.prototypejs.org/">Prototype</a></td>
<td width="40%" style="background-color: #EFEFEF;"><a href="http://jquery.com/">jQuery</a></td>
</tr>
<tr>
<td style="background-color: #EEE;">動畫特效</td>
<td><a href="http://script.aculo.us/">script.aculo.us</a></td>
