之前的文章裡,我稍微追蹤了jQuery的程式碼,來理解jQuery的架構及運作。其實除了前文中比較複雜的selector以及events,jQuery接下來還包裝了traverse、css、positioning、animate...等種類的函數,這部份比較沒有那麼複雜,都是用數個函數來包裝相關的功能,並在內部解決瀏覽器不相容的問題。大體來說,jQuery其實是一個大facade,透過他的定義好的操作方法,就可以簡單地操作DOM,並且可以透過一些方式延伸及擴充功能。(但不是繼承,你要嘛就是用他的功能,要嘛就是擴充他,不過很難繼承)
解下來實作一下plugin,就可以了解到底有多簡單。
我好幾年前寫過一個簡單的date picker函數,在需要使用的頁面上new一個instance之後,在要使用的node上,或要觸發但是把結果寫入另一個node的button上面使用getCalendar()就可以叫出來使用:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://www.fillano.idv.tw/calendar/calendar2.js"></script>
<table border="1">
<tr><td>test: <td><input type=text id=date1><input id="date2" type="button" value="date" onclick="iCalendar.getCalendar('date2','date1')">
<tr><td>test1: <td><input type=text id=date3><input id="date4" type="button" value="date" onclick="iCalendar.getCalendar('date4','date3')">
</table>
<script>
var iCalendar = new calendar();
iCalendar.init();
</script>
(source可以參考連結中的calendar2.js,程式有點長,我不想放進來。)
原來的程式結構大概長這樣:
function calendar () {
......
this.getCalendar = function (sLauncher, sReceiver) {
_now = new Date();
_render();
var launcher = document.getElementById(sLauncher);
_receiver = document.getElementById(sReceiver);
var realY = realPosY(launcher);
var realX = realPosX(launcher);
_container.style.top = realY + "px";
_container.style.left = realX + "px";
_visible();
}
this.init = function () {
document.body.appendChild(_container);
_render();
}
......
}
function realPosX (oTarget) {
......
}
function realPosY (oTarget) {
......
}
改成jQuery plugin時,只要稍微改幾行然後用jQuery.fn.extend加入包裝使用方法的函數就可以運行了:
(function(){
function calendar () {
......
this.getCalendar = function (sLauncher, sReceiver) {
_now = new Date();
_render();
if (typeof sLauncher == 'string') {
var launcher = document.getElementById(sLauncher);
} else {
var launcher = sLauncher;
}
if (typeof sReceiver == 'string') {
_receiver = document.getElementById(sReceiver);
} else {
_receiver = sReceiver;
}
var realY = realPosY(launcher);
var realX = realPosX(launcher);
_container.style.top = realY + "px";
_container.style.left = realX + "px";
_visible();
}
this.init = function () {
document.body.appendChild(_container);
_render();
}
......
this.inited = false;
}
function realPosX (oTarget) {
......
}
function realPosY (oTarget) {
......
}
var iCalendar = new calendar();
jQuery.fn.extend(
{SimpleDatePicker: function() {
if(!iCalendar.inited) iCalendar.init();
jQuery.each(this, function(i, n) {
$(n).click(function(){
iCalendar.getCalendar(this,this);
});
});
return this;
}
});
})(jQuery);
然後在網頁中使用:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="../js/jquery-1.3.2.js"></script>
<script src="http://www.fillano.idv.tw/calendar/calendar3.js"></script>
<script>
$(document).ready(function(){
$('#date1').SimpleDatePicker();
$('#date3').SimpleDatePicker();
});
</script>
<table border="1">
<tr><td>test: <td><input type=text id=date1>
<tr><td>test1: <td><input type=text id=date3>
</table>
想要實際執行看看,可以連到http://www.fillano.idv.tw/calendar/index2.html。
不過我這只是做概念驗證,並不適合當作正式的datepicker來用喔。這個兩三年前寫的東西,架構可以調整的更好,而且可以把一些configuration相關的變數移到程式外,到呼叫時再用物件傳入,這樣程式會更有彈性。另外,在date picker panel上,我完全沒使用css,這樣會在使用css的網頁中出問題,這些都是要進一步調整的地方。另外,就是有許多方法可以改用jQuery的方法,例如偵測node的位置等等。