用JavaScript寫類別的淺薄心得–jQuery UI篇

用JavaScript寫類別的淺薄心得–jQuery UI篇

我個人認為jQuery改變了整個Web的生態

原本的JavaScript其實很不可親

但是jQuery簡單直覺強大的特性,  搭上Web 2.0的風潮

 

現在已經變成我們這行 不能不會的技能之一

基本上我個人是把jQeury的作者當神一樣在拜啦 = =

 

而jQuery提供的介面 讓許多非常優秀的 jQeruy UI 發布在網際網路上

或多或少我們都會用到, 而那些UI更是讓現在網路技術更精彩的不可或缺一環

 

身無一個勉強堪用的小小工程師,  雖然未必要寫一個UI拿去網路上給大家使用

 

但是具備點寫jQueryUI的技能,  寫點UI讓我們自己使用

其實也可以省不少專案開發上的功夫

 

而這篇主要就是在講要怎麼結合jQuery提供的介面跟規範

寫出一個可以跟jQuery原有功能搭配的UI

 

=====================================================================================================

一、寫在前面

 

其實所謂的UI,  說穿了就是前兩篇文章所提到的類別應用而已

 

一般來說使用UI的時候我們可以很簡單的下

	$("#datepicker").datepicker();

 

接著就可以把他變成一個datepicker, 

事實上就是把一個datepicker的類別加成#datepicker這個dom物件的一個屬性而已

 

而這個類別的建構子做了什麼事情呢,  其實可以分兩個方向來說

 

1.  操作html  -  單純一個input是沒辦法跑出一個月曆的,  所以這個建構子第一個要做的事情

                        就是操作html劃出一個隱藏的月曆, 或著可能改變原本的container的一些屬性或是加上class

                        而jQuery UI, 其實免不了會做這些事情

 

2. 定義出屬性跟方法  -  如同前兩篇所說, 這個建構子會定義出這個類別的屬性跟方法,  再提供出去讓人使用

                        這datepicker總要人可以取值吧

 

 

有了這個基本觀念後,  就來試著寫個簡單的UI

 

	$.helloDiv = function (container, options) {
        var defaults = {
            borderStyle: 'outset', borderColer: 'black', borderWidth: '3px',
            width: '500px', height: '300px'
        };

        this.$container = $(container); //把目標值先存起來
        options = options || {}; //假如option是空的,  就給他一個空物件

        this.options = $.extend(defaults, options); //假如是空值, 放入預設值

        var _this = this;

        _this.$container.css({
            'border-color': _this.options.borderColor,
            'border-style': _this.options.borderStyle,
            'border-width': _this.options.borderWidth
        });
        _this.$container.width(_this.options.width);
        _this.$container.height(_this.options.height);

        _this.$container.click(function () {
            _this.SayHello();
        });
    };

    $.helloDiv.prototype = {
        $container: false,
        options: false,
        SayHello: function () { //定義出一個方法
            if (!this.$container || !this.options) return;
            var text = this.$container.text() || '';
            this.$container.text(text + 'Hello! ');
        },
        Alert: function () {
            if (!this.$container || !this.options) return;
            alert(this.$container.text() || '');
        }
    };

    $.fn.helloDiv = function (options) {
        return this.each(function () {
            if (!this.helloDiv) {
                this.helloDiv = new $.helloDiv(this, options); //建構子
            }

            if (typeof options == 'string') { //我個人習慣的方法宣告方式
                switch (options.toLowerCase()) {
                    case 'alert':
                        this.helloDiv.Alert();
                        break;
                }
            }
        });
    };

 

=====================================================================================================

二、jQuery提供的介面

 

這個UI的名稱叫做helloDiv, 同時也是類別名稱

 

可以看到在程式的42行, 寫了$.fn.helloDiv, 他的意思是是告訴jQuery

我有一個UI要加進他的功能中, 請他幫我配置

 

因此之後我可以用

	$('#div').helloDiv();

來使用這個UI

 

=====================================================================================================

三、jQuery必須遵守的規範 - 串接

 

我們在使用jQuery的function的時候,  常常可以$('#target').next().parent().children().css().wrap();

像這樣把不同的function串接在一起, 操作jQuery物件

 

UI必須要遵守這個串接原則,  也就是說我們可以預設進到$.fn.helloDiv的this是一個jQuery物件,  他裡面可能會有很多個div

而在程式的最後,  我們需要把這個jQuery物件給return回去,  讓下一個jQuery function可以使用

 

所以可以看到程式是這樣寫的

 

	$.fn.helloDiv = function (options) {
        return this.each(function () {
            if (!this.helloDiv) {
                this.helloDiv = new $.helloDiv(this, options); //建構子
            }

            if (typeof options == 'string') { //我個人習慣的方法宣告方式
                switch (options.toLowerCase()) {
                    case 'alert':
                        this.helloDiv.Alert();
                        break;
                }
            }
        });
    };

可以看到進去程式之後就是直接return this.each();  然後在一個一個去跑真正的function, 跑完之後會再把jQuery物件給return回去

假如真的有需要return回去的是一個非jQuery物件的值,  務必要特別註明

 

而在each裡面的this,  代表的是那個dom物件,  而程式裡面直接宣告了一個類別並指向給dom的helloDiv

這是為了一個紀錄說這個dom是否有綁上這個物件的動作

 

而不會重複的綁上同一個物件

同時再之後也可以呼叫這個物件的屬性與方法

 

可以看到後面有一個switch,  這個可以先無視,  之後會再提到

 

=====================================================================================================

四、預設值的重要性

 

在這邊先解釋一個這個UI是幹嘛的, 

總之就是幫一個div加框線,  並且點div他會一直說hello而已  (很沒意義的功能我知道 orz)

 

所以我們勢必會操作div的css,  幫他加上框線

那問題就變成是:  要加什麼樣的框線

 

一個有彈性的UI,  當然要可以讓使用者自行定義他要的框線顏色, 寬度跟樣式

 

 

但是一個有彈性的UI, 當然不能硬性規定使用者一定要輸入框線顏色, 寬度跟樣式

所以我們必須要有一個預設值

 

當使用者有輸入值的時候,  就用他的,  沒有輸入的時候就用預設值

 

於是可以看到$.helloDiv有這段程式

	var defaults = {
            borderStyle: 'outset', borderColer: 'black', borderWidth: '3px',
            width: '500px', height: '300px'
        };

        this.$container = $(container); //把目標值先存起來
        options = options || {}; //假如option是空的,  就給他一個空物件
        this.options = $.extend(defaults, options); //假如是空值, 放入預設值

 

簡單來說, 一開始我們先用一個物件定義好default值

 

而使用者傳入的是options,  我們先在第7行判斷, 假如options是null, 就給他一個空物件(非必要)

接著在第八行,  用jQuery提供的方法$.extend去把兩個做比對

 

假如options有, 就以options為主, 不然就以defaults為主,  然後組成一個新的options物件放入this中

 

於是我們把options存起來了,  同時也把$container存起來,  這兩個是UI基本要素

接著就開始進行UI的建構

 

=====================================================================================================

五、變更$container的屬性

 

誠如一開始所說, 這個UI的功能是變更框線顏色, 並且click的時候會說hello

 

我們可以先看14~20行

	var _this = this;

        _this.$container.css({
            'border-color': _this.options.borderColor,
            'border-style': _this.options.borderStyle,
            'border-width': _this.options.borderWidth
        });
        _this.$container.width(_this.options.width);
        _this.$container.height(_this.options.height);

 

我們在建構UI的時候改變他的屬性

這邊基本上可以做任何想做的事情

 

不管是要append一個新的div還是做什麼都可以,  就是發揮創意

 

=====================================================================================================

六、規劃方法

 

接著改變完html後,  接著我們要開始定義方法

 

我希望說當使用者click div的時候, append一個Hello字樣進div

而當使用者click一個外部button的時候, alert出div的text

 

於是我在prototype裡面定義了兩個method

 

	$.helloDiv.prototype = {
        $container: false,
        options: false,
        SayHello: function () { //定義出一個方法
            if (!this.$container || !this.options) return;
            var text = this.$container.text() || '';
            this.$container.text(text + 'Hello! ');
        },
        Alert: function () {
            if (!this.$container || !this.options) return;
            alert(this.$container.text() || '');
        }
    };

接著我們要思索的是,  這兩個方法一個是UI內部會使用到的function

 

一個是給外部觸發的function,  要怎麼定義

 

=====================================================================================================

七、內部使用的function

 

這比較單純,  可以看到我在$.helloDiv這個建構子裡面有這一行

 

	_this.$container.click(function () {
            _this.SayHello();
        });

當$container click的時候,  觸發SayHello這個function

 

這個是屬於建構UI的動作,  因此我把他寫在建構子裡面

 

=====================================================================================================

八、外部使用的function

 

一個UI勢必會做出一個method讓外面的程式呼叫用

 

在這邊舉例是我們希望觸發 UI內部的Alert這個method, 便可以alert text出來

那要怎麼做會比較適當

 

很簡單的思考,  alert這個function是存在div本身的helloDiv這個屬性裡面

那其實只要div.helloDiv.Alert()這樣就可以了

 

但是使用者不會知道我們把類別本體存在哪邊

他們還是要透過$("#div").helloDiv xxx去做呼叫才比較直覺

 

因此我們可以給他們一個api,  $('#div').helloDiv('{methodName'); 就可以呼叫我們的function

就跟jQueryDialog一樣

 

$('#div').dialog();可以宣告一個dialog,  $('#div').dialog('open');  可以把那個dialog給打開

於是我們在$.fn.helloDiv裡面的each加上這段

 

	$.fn.helloDiv = function (options) {
        return this.each(function () {
            if (!this.helloDiv) {
                this.helloDiv = new $.helloDiv(this, options); //建構子
            }

            if (typeof options == 'string') { //我個人習慣的方法宣告方式
                switch (options.toLowerCase()) {
                    case 'alert':
                        this.helloDiv.Alert();
                        break;
                }
            }
        });
    };

 

我們只提供helloDiv一個參數,  當他第一次呼叫的時候,  options會是一個物件, 並且會跑建構子

當他第二次以後呼叫的時候

 

options可以是一個字串, 而我們可以用這個字串當成methodName去找

假如比對有符合的,  就呼叫,  沒有的話自然就跳掉不會有影響

 

 

到這邊我們完成了一個簡單的jQuery UI

 

可以直接用這個來進行測試

<div id='helloDiv'></div>
<input type="button" id='btnHello' value="Hello" />

	$('#helloDiv').helloDiv();
        $('#btnHello').click(function () {
            $('#helloDiv').helloDiv('alert');    
        });

 

=====================================================================================================

九、開放給網路使用

 

放上網路給人下載使用的時候, 第一個要考慮的是$可不可能被用走了,  這樣$.xxxx就不一定能抓到jQuery本來的function

可是要把程式碼裡面所有的$改成jQuery也太難閱讀了點

 

因此可以用這個小技巧

 

	; (function($) {

	//code

})(jQuery);

用一個function包起來, 並且把$當成變數, 用jQuery投進去,  這樣就不會有問題了

 

 

=====================================================================================================

十、寫在最後

 

如同java script的類別一般,  jQuery UI除了要用$.fn, 要串接外,  其實也沒有制式的寫法,  就發揮創意就好

上面介紹的是我習慣的寫法,  包括呼叫method, 切割prototype這些  其實也不一定要這樣寫

 

哩哩喳喳寫了一堆,  大部分都是這些日子的經驗分享,  可能有不正確的地方,  也可能有一點幫助

總之就是希望能跟大家交流

 

 

本來想寫篇如何應用jQuery UI Theme佈置我們的網頁

不過怕沒什麼機會,  就附篇API做參考

 

http://jqueryui.com/docs/Theming/API

 

有的時候都已經匯入了jQuery-UI-custom.css,  裡面定義一堆css

而且圖片也下載了

 

不用可惜,  其實可以拿他裡面的css來佈置我們自己的網頁

 

 

假如有機會再跟大家分享使用心得了

 

--

本文可能有理解錯誤  或不盡不實的地方

請路過的前輩不要客氣  用力打醒

這會是我們成長的主要養分