用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來佈置我們自己的網頁
假如有機會再跟大家分享使用心得了
--
本文可能有理解錯誤 或不盡不實的地方
請路過的前輩不要客氣 用力打醒
這會是我們成長的主要養分