顯示具有 jQuery-ui 標籤的文章。 顯示所有文章
顯示具有 jQuery-ui 標籤的文章。 顯示所有文章

2016年5月1日 星期日

jQuery Widget Factory - Part 4

jQuery Widget Factory - Part 4

簡介

這一篇應用前幾篇的知識,實作一個很簡單的 Widget。這個 widget 是一個網路商店中展示產品的基本元件,做的不是很炫麗,主要是在示範如何在實作一個 widget 時會用到的一些基本技術。圖像的部份用的是 holder.js 用 svg 的方式所模擬出來的圖像,因此在 <img> 標記中沒有設定 src 屬性,而是設定 data-src 屬性,否則流覽器會抛出錯誤訊息,抱怨找不到影像檔。

範例

這個範例中,用水平分隔線分隔了上、下兩塊區域,水平線的上方是一個用來展示產品的 widget,wdiget 中除了產品的圖像(這部份得用一點想像力),還標示了產品的名稱及價格,最下端還有一個標示為 Buy 按鈕,按下按鈕後會讓 widget 觸發一個型態名為 buy 的事件。在「開發者工具」(Development Tools) 的「主控台」(console) 中會顯示訊息,並將產品資訊列印出來。
水平線的下方有兩個標示為 Raise 及 Destroy 的按鈕,每按下 Raise 按鈕一次,會將產品價格提高一元。按下 Destroy 按鈕,會「摧毀」水平線上方的 widget。此時打開「開發者工具」(Development Tools) 的「元件」(Elements) 窗格,可以看到 HTML 程式碼的變化。

CSS

<style>
html {
    width: 100%;
    height: auto;
}
body {
    margin:0 auto;
    width: 800px;
    height:100%;
    padding-top: 20px;
    font:normal normal 16px Arial, '文泉驛正黑', 'WenQuanYi Zen Hei', '儷黑 Pro', 'LiHei Pro', '微軟正黑體', 'Microsoft JhengHei';
}
.item {
    box-sizing:border-box;
    width: 180px;
    height: auto;
    padding: 10px;
    border-radius: 8px;
    background-color:#eee;
}
.item:hover {
    outline:2px solid blue;
}
.item-thumbnail {
    width:160px;
    height:160px;
}
.item-caption {
    maring-top:10px;
    padding-top: 10px;
    padding-bottom:2px;
    border-bottom: 2px solid lightgreen;
    color: black;
    font-size: 1.1em;
}
.item-name {
    color: blue;
}
.item-price {
    color: red;
}
.item-button {
    margin-top:8px;
    text-align: center;
}
.item-desc {    
    font-size: 1em;
}
</style>

CSS 中對應 widget 及各 widget 的子元件,以 CSS 類別定義其外觀。

HTML

<body>
    

</body>

HTML 中 id="item" 的 <div> 是 widget 的掛載點。另定義一條水平分隔線及二個按鈕。

Script

<script>
// widget created by widget factory
(function($, undefined) {
    $.widget( "prod.item", {
        version:"1.0.0",
        options:{
            image:"holder.js/160x160?theme=lava",
            name:"Coffee",
            price:80,
        },     
        _create:function(){
            var html = 
                '
' + '
' + '
' + '
'; var elem = this.element; elem.addClass("item").html(html); // construct DOM elem.find("button").button(); this._on({"click button": this._handler}); this._super(); }, _init:function(){ this._setData(); this._super(); }, _setOption:function(key, value){ this._super(key, value); }, _setOptions:function(opts){ this._super(opts); this._setData(); }, _destroy:function(){ this._super(); var elem = this.element; elem.empty(); elem.removeClass("item"); }, _setData: function() { var elem = this.element; var opts = this.options; elem.find(".item-thumbnail img").attr("data-src", opts.image); elem.find(".item-name").html(opts.name) elem.find(".item-price").html(opts.price); }, _handler:function(evt){ this._trigger("buy", null, {name: this.options.name, price:this.options.price}); // evt.stopPropagation(); } }); })(jQuery); $(function(){ $("#item").item(); $("#destroy").button().click(function(evt){ $("#item").item("destroy"); }); $("#raise").button().click(function(evt){ var elem = $("#item"); elem.item("option", "price", (elem.item("option", "price") + 1)); }); $("#item").bind("itembuy", function(evt, data){ console.log("buy product %o", data); }); }); </script>

第 12~16 行,直接把 widget 的 DOM 結構寫成一個字串,並用 html() 函式置入到 DOM tree 之中,也可以用 append(), before(), after() 。。。等各函式逐一構建,純粹就看各人的喜好做法為何了。
第 20 行,監聽子元件 <button> 的 click 事件,當事件觸發時,則呼叫 this._handler() 內部函式以觸發型態名為 buy 的事件。外部程式則監聽型態名為 itembuy 的事件。
第 24 行,呼叫內部函式 this._setData() 把 this.optins 中的資料顯示在 widget 中。
第 32 行,在修改 this.options 之後呼叫 this._setData() 函式,將更新後的資料顯示在 widget 中。
第 34~39 行,實作 destroy() 函式,將 DOM tree 回復到 widget 建立前的狀態。

2016年4月28日 星期四

jQuery Widget Factory - part 3

Widget Factory - Part 3

簡介

這篇談 widget 有關事件觸發及事件處理的部份。首先,在 widget 進行具體化時,預設會觸發一個型態為 create 的事件,觸發的時機在執行完 _create() 之後,執行 _init() 之前。事件觸發後,widget 會先送一個事件給外部程式,然後去 this.options 物件裡找一個和事件型態名稱相同的屬性,以 create 這個事件為例,也就是屬性名為 create 的屬性,如果這個屬性的值正好是一個函式,這個函式就會被當成一個事件處理函式執行。如果找不到對應名稱的屬性,或對應名稱屬性的值不是函式,widget 就當這事件沒有必要處理,繼續往下執行。不只是預設觸發的 create 事件會這麼做,而是所有在 widget 內部觸發的事件,都會走完上述的這一趟程序。

當 widget 觸發一個事件,而將事件送到 widget 外部時,widget 會在訂定的事件型態名稱前面加上 widget 的名稱字串,然後將字串的字母都變成小寫。事件型態的名稱的字串中可以包含文、數字還有符號 "_" 及 "-"。例如: widget 的名稱為 "item",事件型態為 "create";此時,外部程式要監聽的事件名稱應為 "itemcreate"。

在 Widget Factory 中有三個跟觸發事件和處理事件相關的內建內部函式,這三個內部函式僅供呼叫使用,無需實作:

_trigger(type [, event ] [, data ])
觸發一個事件。
type
事件的型態名稱,賦予值為字串,字串中可以包含文、數字及 "_" 和 "-" 兩個符號。在這裡也可以用大寫字母,只是轉成事件型態名時,大寫字母都會被轉成小寫字母;為了避免麻煩,最好一律用小寫字母,反正還有兩個符號可以用來分隔字詞,還是看得清,讀得懂的。要記得在外部監聽 widget 的事件時,事件型態名稱前面還會加上 widget 的名稱,widget 的名稱中如果有大寫字母,也會被轉換成小寫字母。用中文取事件型態名稱也行,還真的可以成功運作,我有試過,感謝 UTF-8。
event
這是一個選項參數。如果是因為另一個事件的觸發才導致這個事件的觸發,可以將原事件的 event 參數,在此轉發出去給這個事件的處理函式,如果這是原始的觸發事件,就可以不給,但最好給個 null 值。
data
也是一個選項參數。賦予值是個 Javascript 的物件,可以透過這個物件傳送一些資料給事件處理函式。如果要給這個參數,前一個 event 參數就一定要給,至少要給 null 值。
_on([suppressDisabledCheck ] [, element ], handlers)
用來綁定事件和事件處理函式,綁定的事件可以由 widget 自行觸發,或是外部觸發。
suppressDisabledCheck
此為選項參數,賦予值為布林值,預設為 false。設定為 true 時,會先行檢查 element 是否處於 disabled 的狀態,如果不是,則執行事件處理函式,如果是,則不執行事件處理函式。
element
此為選項參數,賦予值為一個 jQuery 物件。不給時,預設為 this.element。給予時則指定派送事件給該物件。
handler
此為必要參數,參數一定得給;但使用的格式有點奇特。如果觸發事件的元件是 widget 的本身,則直接將事件型態名稱做為屬性名,屬性值為事件處理函式。倘若觸發事件的只是 widget 中的子元件,則屬性名的位置要放入一個字串,字串中以第一個空白字元做區分,第一個空白字元前為事件的型態名稱,第一個空白字元之後則全部都屬於 selector 的部份,語法和 CSS3 的選取器 (selector) 一樣,用來指定觸發事件的視覺元件,但選取的範圍侷限於 widget 的子輩元件。屬性值的部份依然是事件處理函式,這個要看範例程式會更清楚。
_off(element, eventName)
解除監聽事件。
element
為必要參數,指定要解除監聽的物件。賦予值為一個 jQuery 物件。
eventName
為必要參數,指定要解除監聽的事件型態。賦予值為一字串,字串中可包含多個事件型態的名稱,以空白字元分隔。

範例

範例中的視覺元件是兩個同心圓,點按內部的圓形,會改變內部圓形的顏色,點按外部的圓形,則不做任何反應。同心圓下有個按鈕,按下按鈕後,會解除內部圓形對 click 事件的監聽,之後再點按內部的圓形時,就不會有任何反應了。
記得開啟「開發者工具」中的「主控台」去查看輸出,可以對事件的處理時機有進一步的瞭解。

CSS

<style>
html {
  width:100%;
  height:auto;
}
body {
  margin:0 auto;
  width:1200px;
  padding-top:20px;
}
#item {
  width:200px;
  height:200px;
  border-radius: 50%;
  background-color:skyblue;
    text-align: center;
}
#itemCore {
    position: relative;
    top: 50%;
    left:50%;
    transform: translate(-50%, -50%);
    width:100px;
    height:100px;
    border-radius: 50%;
    background-color:lightgreen;  
}
</style>

CSS 中 #item{} 用來設定同心圓外部圓形的外觀, #itemCore{} 用來設定同心圓內部圓形的外觀,並讓內部圓形置於外部圓形的正中央。

HTML

<body>
    

</body>

HTML 中建立兩個 <div> 在流覧器中用圓形表示,還有一個按鈕。

Script

<script>
// widget created by widget factory
(function($, undefined) {
    $.widget( "prod.item", {
        version:"1.0.0",  
        options:{
            product:"Coffee",
            price:80,
            create:$.noop,  // default to no operation
            optionchanged:function(){
                console.log("\thandle optionchanged event in this.options");
            }
        },
        _create:function(){
            console.log("_create start");
            this._on({"click #itemCore":function(evt){
                console.log("\thandle a click event trigger by #itemCore");
                var elem = $("#itemCore")
                if(elem.hasClass("coral")){
                    elem.css("background-color", "lightgreen").removeClass("coral");
                } else {
                    elem.css("background-color", "coral").addClass("coral");
                }
            }});
            this._super();
            console.log("_create end");
        },
        _init:function(){
            console.log("_init start");
            this._super();
            console.log("_init end");
        },
        _setOption:function(key, value){
            this._super(key, value);
            console.log("_setOption");
            this._trigger("optionchanged", null, {key:key, value:value});
        },
        _setOptions:function(opts){
            this._super(opts);
        },
        _destroy:function(){
            this._super();
        },
        removeHandler:function(ent){
            this._off(this.element, "click");
        }
    });
})(jQuery);

  
$(function(){
    var elem = $("#item");
    // here use "item" + "create" as event type
    elem.bind("itemcreate", function(evt){
        console.log("\thandle create event outside of widget");
    });

    // use "item" + "optionchanged" as event type 
    elem.bind("itemoptionchanged", function(evt, data){
        console.log("\thandle optionchanged event outside of widget");
        console.log("\t%o", evt);
        console.log("\t%o", data);
    });

    $("#off").button().click(function(){
        $("#item").item("removeHandler");
    })
    // override create attribute in this.options
    elem.item({
        create:function(){
            console.log("\thandle create event in this.options");
        }
    });

    // trigger an "optionchanged"/"itemoptionchange" event
    elem.item("option", "price", 2.99);
});
</script>

第 6 行,指定 widget 的版本號碼,以便將來維護。
第 9 行,先定一個 create 屬性,預設值為 $.noop ,就是 no operation,不做任何事的意思。由 widget 在具體化時,由參數傳入來改寫參數值。
第 11~12 行,定義 optionchanged 事件的處理函式。
第 16~24 行,綁定由 #itemCore 所觸發的 click 事件,及事件的處理函式,注意第 16 行中,參數的寫法。
第 36 行,在呼叫 _setOption() 時觸發一個事件型態為 optionschanged 的事件,並變更後的屬性名及屬性值以 Javascript 物件的方式,當成參數傳出去。
第 44~47 行,定義一個名為 removeHandler 的外部函式,在函式中呼叫 this._off() 解除對 #itemCore 元件所觸發之 click 事件的監聽。
第 54~56 行,在 widget 外部綁定監聽 itemcreate 事件及其處理函式。
第 59~63 行,在 widget 外部綁定綁定監聽 itemoptionchanged 事件及其處理函式。
第 65~67 行,定義一個 jquery-ui 的按鈕,在觸發 click 事件時,於事件處理函式中呼叫 widget 中的 removeHandler 外部公用函式。,br> 第 69-73 行,具體化名為 item 的 widget,同時傳入一物件做為參數,物件中是對 create 事件的事件處理函式。
第 76 行,呼叫 widget 的 option 函式以觸發一個 optionchanged 的事件。

2016年4月27日 星期三

jQuery Widget Factory - Part 2

Widget Factory - Part 2

簡介

這篇談 widget 的生命週期 (lifecycle)。在繼承了 $.widget 之後,有幾個繼承而來的基本函式是一定要好好實作的,否則宣告的 widget 就很難有所作為,或者在使用時也會造成很多的不便和困擾。這篇談的就是這些非實作不可的基本函式;但並未真正實作出函式,只放了一些簡單的程式碼做為研究之用;而是先討論在整個 widget 的生命週期中,這些函式是在何時被呼叫、執行及真正要實作時,大概哪些作業要放在哪個函式中實作。

this.options

在談到必要的基本函式之前,一定要先提到一個很重要的屬性 - options,這個屬性的值是一個 Javascript 的物件,用來儲存這個 widget 在運作時所要使用到的屬性及屬性的預設值,還有當指定事件被觸發時,所要執行的回呼函式 (callback)。實際上,從 $.widget 中就繼承了一個 options 的物件,這個物件中只有 disabled 及 create 兩個屬性,在這個 widget 中所宣告和定義的 options,最終會和 $.widget 中所繼承過來的 options 合併 (merge) 成一個物件。若是繼承其它的模組,最終也會和該模組的 options 物件合併成一個物件。在整個 widget 的實作過程中,都以 this.options 來參考這個合併過後的物件。而下述的兩個函式: _setOptions() 及 _setOption() 也是針對 this.options 這個物件的屬性及屬性值在作業。

Basic Methods

widget 生命週期中一定會執行到的基本函式如下,這裡先簡單的介紹各函式的主要作用及執行時機,在範例的程式碼中,可以更清楚的看出各函式的執行時機。這些函式中,通常都會在函式的某處呼叫 this._super() 或 this._superApply() 以執行父物件中同名的函式,確保父物件中同名的函式也會被執行。

_create()
這個函式只有在 widget 第一次被呼叫,將 widget 具體化 (instantiate) 時會執行。函式中首先要做的是在 DOM tree 中構建 widget 所需要的各個節點,及將要監聽的事件和該事件的處理器綁定 (bind) 在一起。因為只會被執行一次,所以在整個 widget 的生命週期中,只能做一次和只需做一次的作業,都放到這個函式裡。具體化時,執行完 _create() 之後,會緊接著執行 _init()。一般 _create() 可以不傳入參數,但也可以傳入一個 Javascript 的物件,物件的內容可以用來修改 this.oprions 的內容。
_init()
jquery-ui 中將建立 (create) 和初始化 (initialize) 視為兩個概念,因此分成兩個階段來執行。_init() 除了在第一次具體化時跟在 _create() 後面被執行一次之外,每次呼叫 widget 但不傳入任何參數時,例如: $(selector).widget(); _init() 也都會被執行一次。此時,會先執行 _setOptions() 之後再執行 _init()。和 _create() 一樣, _init() 一般也不傳入參數,但也可以傳入一個 Javascript 的物件,物件的內容也是用來修改 this.oprions 的內容。注意:_init() 在整個 widget 的生命週期中,可能被執行不止一次,這點和 _create() 不同,因此,整個整個生命週期中只能執行一次的作業絕對不能放在這個函式裡。
_setOption(key, value)
將 this.options 之名為 key 之屬性的值改成 value。這個函式實際上不會被外部程式直接呼叫,它都是透過 _setOptions() 函式的呼叫才會執行。如果某個 this.options 中的屬性值有限制條件,可以在這裡做檢查;或者屬性值變更後,需要觸發某事件等,都在這裡處理。重點是 _setOption() 會實際去改變 this.options 的屬性值,要等到屬性值改變完畢之後才能執行的作業,一定得在這個函式中確定 this.options 中的屬性值被修改完畢後才能進行。
_setOptions(opts)
只要呼叫 $(selector).widget("option", key, value); 或是 $(selector).widget("option", {key1:value1, key2:value2}); ,以變更 this.options 中的屬性值,都會執行 _setOptions() 函式,再由 _setOptions() 為每一個傳入的屬性呼叫一次 _setOptions()。只有呼叫 $(selector).widget("option", key); 以取得 key 屬性的值時,不會執行 _setOptions()。另外,就是在進行被始化時,會在執行 _init() 之前被執行。這個函式大多在進行改變 this.options 屬性值的前置作業。
_destroy()
摧毀此 widget。把 destroy 譯成「摧毀」好像很可怕,但這個函式基本上,就是把 widget 在 DOM tree 中所建構的東西都清除乾淨,讓 DOM tree 回復到尚未建構這個 widget 之前的狀態。 $(selector).widget("destroy"); 呼叫 destroy() 公用函式, destroy() 公用函式則把工作再指派給 _destroy()。所以可以不用理會 destroy() 公用函式 只要實作 _destroy() 函式即可。只是在有繼承父類別時,在清除 DOM tree 中的東西時,得特別注意一下清除的前後次序。如果在 widget 中一次把所有的東西都清光了,有時父類別的 _destroy() 函式會因為找不到東西清除而出現錯誤。

範例

範例在網頁下載完畢後,網頁上會出現一個橘紅色圓圈,這個圓圈其實跟 widget 的生命週期沒什麼關係。只是用來顯示網頁已經下載完畢而己。記得開啟「開發者工具」中的「主控台」看程式執行的結果。範例式程中,每個基本的函式中,都只寫了二行程式碼,第一行將該函式的名稱印在主控台上;第二行呼叫 this._super() 執行父物件中的相對應函式。主程式大略把一個 widget 在生命週期中會被外部程式呼叫的函式,都呼叫了一遍,從主控台中的輸出結果,可以看出每次呼叫時,哪些 widget 的基本函式會依照何種順序執行。

CSS

<style>
html {
    width:100%;
    height:auto;
}
body {
    margin:0 auto;
    width:1200px;
    padding-top:20px;
}
#item {
    width:200px;
    height:200px;
    border-radius: 50%;
    background-color:coral;
}
</style>

CSS 中用 #item{} 顯示了一個用來表示網頁已經下載完畢的橘色圓圈。

HTML

<body>
    
</body>

HTML 中只建立了一個 id="item" 的元件,用來顯示橘色圓圈和掛載 widget。

Script

<script>
// widget created by widget factory
(function($, undefined) {
    $.widget( "prod.item", {
        version:"1.0.0",
        options:{
            product:"Coffee",
            price:80
        },
        _create:function(){
            console.log("\t_create()");
            this._super();
        },
        _init:function(){
            console.log("\t_init()");
            this._super();
        },
        _setOption:function(key, value){
            console.log("\t_setOption()");
            this._super(key, value);
        },
        _setOptions:function(opts){
            console.log("\t_setOptions()");
            this._super(opts);
        },
        _destroy:function(){
            console.log("\t_destroy()");
            this._super();
        }
    });
})(jQuery);

    
$(function(){
    console.log('var elem = $("#item").item()');
    var elem = $("#item").item();

    console.log("elem.item()");
    elem.item();

    console.log('elem.item("option")');
    console.log("\t%o", elem.item("option"));

    console.log('elem.item("option", {product:"Milk", price:50})');
    elem.item("option", {product:"Milk", price:50})
    console.log("\t%o", elem.item("option"));

    console.log('elem.item("option", "price", 60)');
    elem.item("option", "price", 60);

    console.log('elem.item("option", "price")');
    console.log("\t%s", elem.item("option", "price"));

    console.log('elem.item("destroy")');
    elem.item("destroy");
});
</script>

第 5 行,習慣上會加上 version 屬性,並標示 widget 的版本號。
兩段程式都很簡單,一看就懂,不多做說明了。只是從主控台結果裡發現了一件事,要提醒一下:在第 36 行具體化物件時,不論是否有傳入物件參數以改變 this.options 的屬性值,都只會先執行 _create() 接著執行 _init(),是不會執行 _setOptions() 函式的,更不用說 _setOption() 函式了,因此,如果在這兩個函式中,有針對傳入參數的作檢核或是任何前置處理,都不會被執行到。如果在具體化 widget 時,有要傳入物件參數以改變 this.options 之內容的要求,則得在 _create() 函式中自行呼叫 _setOptions() 函式,以完成參數的檢核或前置處理作業。

2016年4月26日 星期二

jQuery Widget Factory - Part 1

Widget Factory - Part 1

簡介

在 jQuery UI 中要撰寫一個視覺元件 (widget) 的模組, 在 jQuery UI v1.8 之前只能使用 plugin,自 jQuery UI v1.8 版之後則可以使用 Widget Factory 模組。該模組所提供的 APIs 在後繼的 v1.9, v1.10, v1.11 版都有少許的變更。這系列文章採用的是 v1.11 版的 APIs,這是寫文章時可供下載最新、最穩定的版本。使用 Widget Factory 時會需要用到兩個模組:core.js 和 widget.js;這兩個模組都存在於 jquery-ui.js 套件之下。所以必須載入 jquery-ui.js 或 jquery-ui.min.js。如果不會用到其它 jQuery 的介面元件,也不想載入整個 jquery-ui 的套件,就得將這兩個模組從 jquery-ui 套件中分離出來後,單獨載入。

這篇文章只解釋 Widget Factory 最重要的基礎部份,也就是只宣告一個 widget,完全沒有實作任何東西時,所宣告的 widget 會長成什麼樣。

使用 Widget Factory 宣告一個 widget 時所用的語法如下:

$.widget(name, [base], prototype);

name
字串值。為此 widget 所取的名字,名字必須包含命名空間,例如: myNameSpace.myWidget。命名空間只能有一層,撰寫應用程式時,基本上是用不到這個命名空間的,但一定得給;因為 jquery-ui 會在 $ (這個 "$" 是 jQuery 在 script 中的簡寫)之中建立一個名為 myNameSapce 的物件,而在 $.myNameSpace 之下,又有個名為 myWidget 的物件,這就是宣告後 widget 所在的位置。所有自訂的 widget,只要命名空間相同,都會被放在一起;這樣比較好管理。同一個名命空間下的 widget 名稱就不能重複了。
base
選項參數。此為所宣告之 widget 要繼承之模組名稱。例如: $.ui.button 或 $.ui.dialog。如果此參數從缺時,預設為繼承 $.Widget(注意:這裡 Widget 的 W 是大寫字母,表示它是一個物件類別的名稱)模組。
prototype
賦予值為一函式 (function),在此函式中必須實作所有的繼承自 $.widget 的函式,這些函式包含供內部使用的函式 (private method),及供外部呼叫的函式 (public method)。供內部使用的函式,依慣例,在函式名稱都前置一個底線 "_",如: _create();供外部呼叫的函式則無前置底線,如:enable()。這種命名方式並非強制的規則,只是一般通用的慣例。

this.options & this.element

當執行完 $.widget() 之後,widget 的基本架構就構建完成了。此時,widget 己具有兩個很重要的屬性:options 及 element。在實作 widget 的各函式時,常會使用 this.options 及 this.element 去參考這兩個屬性。

options
是個 Javascript 的物件,起始時預設內含兩個屬性:disabled 和 create。將來 widget 中要包含其它的屬性時,也都會放到這個物件裡。
disabled
預設值為 false。當呼叫 .disable() 時,此屬性值會被改成 true。程式中可以偵測此屬性值以決定 widget 的狀態。
create
預設值為 null。傳入值為一回呼函式 (callback function),當 widget 具體化 (instantiate) 時,會觸發一個型態為 create 的事件,同時將此回呼函式當成事件的處理函式執行。
element
目前使用到的 jQuery 物件。在 jQuery 中,函式常常依序針對數個 jQuery 物件逐一處理,而 this.element 之中只含了一個 jQuery 的物件,也就是當前正在處理的物件。

Public Methods

假如宣告了一個名為 myWidget 的 widget。要呼叫 myWidget 中之函式的方式為 myWidget(methodName),methodName 是函式名稱的字串。這種方式是傳統 jQuery 呼叫函式的方式。在 v1.11 版後,還可以用 myWidget.("instance").methodName() 的方式來呼叫。以下是定義完 widget 之後,在還沒有實作任何函式時,就可以呼叫而不會抛出錯誤訊息的函式,因為完全沒實作,所以也做不了什麼事。各函式細節的部份,等實作時再做說明。

myWidget.("option", optionName)
myWidget.("option", optionName, value)
myWidget.("option")
myWidget.("option", object)
第一個呼叫方式讀取 optionName 的值,optionName 需為字串值。第二個呼叫方式設定 optionName 的值為 value。第三個呼叫方式讀取所有 option 的值,傳回值為一個物件,內含所有的 option 及其現值。第四個呼叫方式一次設定數個 option 的值,傳入值為一個物件,物件中所含有的 option,其值都會被重新設定為物件中的值。
myWidget("widget")
傳回 jQuery 物件。這個函式不需要實作,就這樣用,其實這個函式只是把 this.element 傳回來而已。
myWidget("instance")
傳回 widget 的 instance。這是唯一不能用 myWidget("instance").instance() 方式來呼叫的函式,這樣呼叫也沒什麼意義。這個函式也不需要實作,它主要的作用就在提供另一種呼叫 widget 中其它公用函式的方法罷了。
myWidget("disable")
Disable widget。此時會在 widget 的屬性 class 中加入 nameSpace-widgetName-disabled 這個字串。字串中的 nameSpace 及 widgetName 由 widget 的 nameSpace 及 widgetName 的字串值來取代。然後把 options.disabled 的值改成 true。
myWidget("enable")
Enable widget。將 widget 之 class 中的 nameSpace-widgetName-disabled 字串刪除;然後把 options.disabled 的值改成 false。
myWidget("destroy")
清除 widget。

範例

範例中宣告了一個名為 prod.item 的 widget。並呼叫上述的各函式,大多數的結果都要到「開發者工具中」的主控台去看。只有 enable() 及 disable() 這兩個函式定義了 CSS 的類別,可以展示一點視覺效果。網頁下載後,過 2 秒會 disable widget,再過 2 秒會 enable widget,再過 3 秒會 destroy widget,因為只宣告了 widget 也沒實作,也沒什麼可以 destroy 的。

head





在 <head> 中記得要載入 jquery-ui.min.js。

CSS

<style>
html {
    width: 100%;
    height: auto;
}
body {
    margin: 0 auto;
    width: 1000px;
    padding: 20px;
}
#item {
    width: 200px;
    height: 200px;
    border: 2px solid gray;
    background-color: skyblue;
}
.prod-item-disabled {
    opacity:0.3;
}
</style>

CSS 中用 #item{} 定義了元件的基本外觀。
.prod-item-disabled{} 定義了當元件被 disabled 時,將元件的 opacity 值降到 0.3。這樣在執行時會造成一點視覺效果。

HTML

<body>
    
</body>

HTML 中定義了一個 id = "item" 的元件,作為 widget 的掛載點。

Script

<script>
// widget created by widget factory, should put into another file
(function($, undefined) {
    $.widget( "prod.item", {
  
    });
})(jQuery);

 
$(function(){
    console.log("jQuery version is " + $().jquery);
    console.log("jQuery-ui version is " + $.ui.version);

    console.log($.prod);

    var elem = $("#item").item();
 
    console.log(elem.item("option"));
    console.log(elem.item("widget"));
    console.log(elem.item("instance"));

    setTimeout(function(){
        elem.item("disable");
        console.log(elem.item("option", "disabled")); // true
    }, 2000);
    setTimeout(function(){
        elem.item("enable");
        console.log(elem.item("option", "disabled")); // false
    }, 4000);
    setTimeout(function(){
        elem.item("destroy");
    }, 6000); 
});
</script>

第 3~7 行,定義了一名為 prod.item 的 widget。一般來說,這一部份的程式碼在實務上實作時,都會分開放在另一個檔案之中,以便維護。
第 11~12 行,在主控台中列印出使用的 jQuery 及 jQuery-ui 的版本。
第 14 行,在主控台中列印 $.prod 物件,所有以 prod 做為命名空間的 widget 都會放在這個物件之中。
第 18~20 行,依序呼叫三個函式,並在主控台印出傳回值。 可以比較一下 widget() 和 instance() 兩個函式的傳回值有何不同。
第 22~25 行,設定一個定時器,在網頁下載 2 秒過後,disable widget ,並將 options.disabled 的值印在主控台中。
第 26~29 行,設定一個定時器,在網頁下載 4 秒過後,enable widget ,並將 options.disabled 的值印在主控台中。
第 30~32 行,設定一個定時器,在網頁下載 6 秒過後,清除 widget。這個只是呼叫了 destroy() 這個函式,完全沒做任何事。