JQuery插件開發教程 | WhyJQuery

【前言】
jQuery已經被普遍使用,憑藉其簡潔的API,對DOM強大的操控性,易擴展性愈來愈受到web開發人員的喜好,我在社區也發佈了不少的jQuery插件,常常有人詢問一些技巧,所以乾脆寫這麼一篇文章給各位jQuery愛好者,算是拋磚引玉吧。 javascript

【基礎】 
a)樣式
很 多人會認爲樣式是個很複雜的東西,須要沉着冷靜的心態加上非凡的審美觀才能設計出賞心悅目的UI,拋開圖片設計不說,其實css也就是那麼些屬 性:position,margin,padding,width,height,left,top,float,border,background… css

UI設計的漂亮與否在很大程度上依賴於設計人員對配色的把握和總體效果的協調。舉個簡單的例子,一個簡單的頁面,馬虎的人: html

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Test Page</title>
</head>
<body>
    jQuery是一個框架!壓縮後有30多k吧。
</body>
</html>


細心的人: java

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Test Page</title>
    <style type="text/css">
        body
        {
            font-family:'宋體';
            font-size:12px;
            }
    </style>
</head>
<body>
    jQuery是一個框架!壓縮後有30多k吧。
</body>
</html>

專心的人: jquery

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Test Page</title>
    <style type="text/css">
        body
        {
            font-family:'Verdana','宋體';
            font-size:12px;
            }
    </style>
</head>
<body>
    jQuery是一個框架!壓縮後有30多k吧。
</body>
</html>


咱們對比一下三者的UI效果:



一目瞭然,或許不少的站點失去關注正是由於這不起眼的font-family,font-size。固然這還只是個簡單的例子,掌握css應該從簡單作起,從基本入手,在實踐中運用並不斷深刻。 web

b)腳本 
咱們一樣須要對javascript有着深入的理解,對dom, xhr, Regex, call-apply, prototype等都應該有必定的瞭解。 ajax

有人會說要這些有啥用啊,對dom的操做其實經過getElementById, getElementsByTagName以及其餘的API均可以輕鬆的完成,這話是沒錯,當思路肯定後,思想纔是重點,一段代碼是精華仍是糟粕很容易就 能夠區分出來,究其緣由仍是取決你本身,舉個簡單的例子,大量的html組裝,路人甲: 緩存

var a = new Array(10);
var menu = '';   
for (var i = 0; i < a.length; i++) {
  menu += '<li class="style_' + a[i] + '" >' + a[i] + '</li>';
}


路人乙: 閉包

String.prototype.format = function() {
    var args = arguments;
    return this.replace(/{(\d{1})}/g, function() {
        return args[arguments[1]];
    });
};var a = new Array(1,2,3,4,5,6,7,8,9,0);
var m = '<li class="style_{0}" >{0}</li>';for (var i = 0; i < a.length; i++) {
    menu += m.format(a[i]);
}


在實現方式明確的狀況下,優雅高效的代碼顯然更具吸引力。 app

【實踐】
jQuery開發或使用,更多的靈感是來自實踐,而不是copy||paste(奉行拿來主義的同窗能夠離開了)。

那麼在這裏我會用一個簡單的例子來闡述jQuery插件開發的流程,可否觸類旁通就看各位看官了。

【目的】 

開發一個插件以前咱們須要對本身的目的有一個清醒的認識,有很明確的方向感,那麼這次我做爲示例插件的目的,就是呈現一個用於UI的Slider – 滑動條,常年從事於或暫時專一於win32開發的同窗應該比較瞭解。

草圖

真正動手編碼以前咱們還須要有一個草圖來描述本身插件的「長相」(事件驅動或API封裝的能夠忽略)。
不少的同窗在作UI開發前每每會忙於蒐集各類小圖片(非精通ps或iconworkshop人士),其實漂亮的圖標的確能夠美化咱們的UI,不過我通常的處理方式是編寫易於擴展的css,前期的UI呈現儘可能少使用圖片,多用線條完成。

ok,言歸正卷,那麼個人slider設計草圖是:

 

解釋下下文將用到的幾個詞:
slider: 此部分是做爲拖拽手柄來使用,用戶能夠經過拖拽此部分來更新completed bar的位置。
completed: 此部分做爲bar的內嵌元素,做爲特殊效果來顯示slider與起始點的距離,亦即與slider的value值關聯。
bar: slider的載體,completed的滿值。

思路:
slider做爲手柄提供拖拽功能,做用區域爲bar,拖拽過程當中completed條必須實時更新(長度),影響區域爲slider至bar左端的距離。

【編碼】 

開發jQuery UI/Effect 插件在不少時候都須要與UI交互,所以在呈現上須要提供Html tree來繪製咱們的插件,最終經過js dom來輸出,那麼在繪製簡單的dom結構的時候我會直接用js來完成,不過若是嵌套比較複雜的話,咱們仍是應該先用html來完成,而後轉變成js輸 出。

html tree:

<div class="defaultbar">
  <div class="jquery-completed"> </div>
  <div class="jquery-jslider"> </div>
</div>

deafultbar -> bar
jquery-completed -> completed
jquery-jslider -> slider

前期UI呈現上咱們不使用圖片,儘可能用線條、顏色來完成:

Css

將bar的position屬性設置成relative,以方便子節點的浮動(子節點使用>

那麼咱們能夠看下這個css和html tree產生的UI效果:
 

ok,具有了所需的元素 – slider, completed, bar.

一些規範:

當咱們畫出了UI以後就能夠正式編寫jQuery插件代碼了,不過在着以前咱們還須要對jQuery插件開發的一些規範性有一些瞭解。

1. 使用閉包:

(function($) {
  // Code goes here
})(jQuery);

這是來自jQuery官方的插件開發規範要求,使用這種編寫方式有什麼好處呢?

a) 避免全局依賴。

b) 避免第三方破壞。

c) 兼容jQuery操做符'$'和'jQuery '

咱們知道這段代碼在被解析時會形同以下代碼:

var jq = function($) {
  // Code goes here
}; 
jq(jQuery);

這樣效果就一目瞭然了。

2. 擴展

jQuery提供了2個供用戶擴展的‘基類’ – $.extend和$.fn.extend.

$.extend 用於擴展自身方法,如$.ajax, $.getJSON等,$.fn.extend則是用於擴展jQuery類,包括方法和對jQuery對象的操做。爲了保持jQuery的完整性,我比較 趨向於使用$.fn.extend進行插件開發而儘可能少使用$.extend.

3. 選擇器

jQuery提供了功能強大,併兼容多種css版本的選擇器,不過發現不少同窗在使用選擇器時並未注重效率的問題。 

a) 儘可能使用Id選擇器,jQuery的選擇器使用的API都是基於getElementById或getElementsByTagName,所以能夠知道 效率最高的是Id選擇器,由於jQuery會直接調用getElementById去獲取dom,而經過樣式選擇器獲取jQuery對象時每每會使用 getElementsByTagName去獲取而後篩選。

b) 樣式選擇器應該儘可能明確指定tagName, 若是開發人員使用樣式選擇器來獲取dom,且這些dom屬於同一類型,例如獲取全部className爲jquery的div,那麼咱們應該使用的寫法 是$('div.jquery')而不是$('.jquery'),這樣寫的好處很是明顯,在獲取dom時jQuery會獲取div而後進行篩選,而不是 獲取全部dom再篩選。

c) 避免迭代,不少同窗在使用jQuery獲取指定上下文中的dom時喜歡使用迭代方式,如$('.jquery .child'),獲取className爲jquery的dom下的全部className爲child的節點,其實這樣編寫代碼付出的代價是很是大 的,jQuery會不斷的進行深層遍從來獲取須要的元素,即便確實須要,咱們也應該使用諸如$(selector,context), $('selector1>selector2'), $(selector1).children(selector2), $(selctor1).find(selector2)之類的方式。

開始編碼 

話題有點扯遠,ok,在對UI有了清晰的認識後咱們就可使用js來輸出html了。

咱們使用jSlider來命名這個slider插件(爲了不插件衝突,插件命名時也應十分考究,這裏我就俗一回)。

$.extend($.fn, {
        ///<summary>
        /// apply a slider UI
        ///</summary>
        jSlider: function(setting) {
        }
});

在插件開發中比較標準的方式是將元數據獨立出來並開放API,好比這裏的setting參數傳入值,有時候爲了減小代碼編寫量,我習慣於直接在插件內賦值:

var ps = $.extend({
    renderTo: $(document.body),
    enable: true,
    init;'max',
    size: { barWidth: 200, sliderWidth: 5 },
    barCssName: 'defaultbar',
    completedCssName: 'jquery-completed',
    sliderCssName: 'jquery-jslider',
    sliderHover: 'jquery-jslider-hover',
    onChanging: function() { },
    onChanged: function() { }
}, setting);


規範的作法:

$.fn.jSlider.default = {
    renderTo: $(document.body),
    enable: true,
    init;'max',
    size: { barWidth: 200, sliderWidth: 5 },
    barCssName: 'defaultbar',
    completedCssName: 'jquery-completed',
    sliderCssName: 'jquery-jslider',
    sliderHover: 'jquery-jslider-hover',
    onChanging: function() { },
    onChanged: function() { }
    };

$.extend({},$.fn.jSlider.

default,setting);


ok, 下面描述下我所定義的這些API的做用:
renderTo: jSlider的載體、容器,能夠是一個jQuery對象,也能夠是選擇器。
enable: jSlider插件是否可用,true時end-user可拖拽,不然禁止。
initPosition: jSlider的初始值,‘max’或者‘min’,亦即 slider的value值,1或者0。
size: jSlider的參數,包括2個值barWidth – bar的長度, sliderWidth – slider的長度。
barCssName: bar的樣式名稱,便於end-user自行擴展樣式。
completedCssName: completed的樣式名稱。
sliderCssName: slider的樣式名稱。
sliderHover: slider聚焦時的樣式名稱。
onChanging: slider被拖拽時觸發的事件。
onChanged: slider拖拽結束時觸發的事件。

此時咱們須要將renderTo強制轉換成jQuery對象(兼容使用selector的狀況):

ps.renderTo = (typeof ps.renderTo == 'string' ?
                 $(ps.renderTo) : ps.renderTo);


而後將html tree輸出到render:

/* ———->
html tree:
<div> —->sliderbar
<div>&nbsp;</div>   —-> completed bar
<div>&nbsp;</div>   —-> slider                  
</div>
<———–*/
var sliderbar = $('<div><div>&nbsp;</div><div>&nbsp;</div></div>')
                    .attr('class', ps.barCssName)
                        .css('width', ps.size.barWidth)
                            .appendTo(ps.renderTo);var completedbar = sliderbar.find('div:eq(0)')
                        .attr('class', ps.completedCssName);var slider = sliderbar.find('div:eq(1)')
                .attr('class', ps.sliderCssName)
                    .css('width', ps.size.sliderWidth);

這樣咱們就在UI上直接呈現了Html而且用定製的css進行渲染,分別用sliderbar, completedbar, slider對咱們須要的三個對象進行緩存。

ok, 在呈現了UI後咱們就須要提供方法來實現slider的拖拽,在這以前咱們還須要實現一個方法,就是completedbar的實時更新,即在拖動slider的時候讓completedbar始終填充左側區域:

var bw = sliderbar.width(), sw = slider.width();
//make sure that the slider was displayed in the bar(make a limited)
ps.limited = { min: 0, max: bw - sw };if (typeof window.$sliderProcess == 'undefined') {
    window.$sliderProcess = new Function('obj1', 'obj2', 'left',
                                     'obj1.css(\'left\',left);obj2.css(\'width\',left);');
}
$sliderProcess(slider, completedbar, eval('ps.limited.' + ps.initPosition));

bw,sw用來存儲sliderbar和slider的長度,此處沒有直接使用ps.size裏的值是爲了防止樣式裏的border-width對width形成破壞。

定義一個私用成員limited來存儲slider[left]的最大值和最小值,並在後面直接使用eval('ps.limited.' + ps.initPosition)來獲取,從而避免switch操 做。

同時還需定義一個全局Function用來定位completedbar的填充長度以及slider左側距離,我給其命名爲$sliderProcess。

那麼咱們接下來剩下的工做就是slider的拖拽功能了,那麼在這裏我會用到以前發佈的一款jQuery拖拽插件,並作適量的訂製:

//drag and drop
var slide = {
    drag: function(e) {
        var d = e.data;
        var l = Math.min(Math.max(e.pageX - d.pageX + d.left, ps.limited.min), ps.limited.max);

        $sliderProcess(slider, completedbar, l);
        

//push two parameters: 1st:percentage, 2nd: event
        ps.onChanging(l / ps.limited.max, e);
    },
    drop: function(e) {
        slider.removeClass(ps.sliderHover);
        //push two parameters: 1st:percentage, 2nd: event
        ps.onChanged(parseInt(slider.css('left')) / ps.limited.max, e);

        $().unbind(

'mousemove', slide.drag).unbind('mouseup', slide.drop);
    }
};if (ps.enable) {
    //bind events
    slider.bind('mousedown', function(e) {
        var d = {
            left: parseInt(slider.css('left')),
            pageX: e.pageX
        };
        $(this).addClass(ps.sliderHover);
        $().bind('mousemove', d, slide.drag).bind('mouseup', d, slide.drop);
    });
}

這樣當jSlider enable屬性爲true時,在end-user按下鼠標時綁定mousemove事件,在鼠標彈起時移除,咱們只須要同步更新slider的left 屬性和completedbar的width便可,同時在drag中綁定onChanging方法,在drop中綁定onChanged方法,向這兩個方 法推送的參數相同,1>百分比,即value值,介於0~1,2>event。

那麼至此咱們的jSlider插件就基本成型,向用戶提供了一個可拖拽的slider。

【擴展】 
有的時候用戶卻不是那麼容易知足,因而有人高呼:「我要本身設置value,爲何不提供這個功能?」。

那麼這時咱們就須要爲用戶公開一個方法,用於設置jSlider的value,首先考慮的是做爲方法須要一個做用對象(jSlider),那麼此時我又不 想將做用對象做爲參數傳入,那麼咱們仍是將這個方法做爲插件來開發,咱們將方法命名爲setSliderValue,開放2個參數,v(value值)和 callback(設置完成後的回調函數)。

即:$.fn.setSliderValue(v,callback);

ok,那麼剩下的就是做用對象了,由以前的設計可知,在slider拖動時主要做用於2個對象,slider和completedbar,那麼咱們在jSlider插件末尾加上一段代碼來返回slider對象:

slider.data = { bar: sliderbar, completed: completedbar };
return slider;

這樣咱們在初始化jSlider的時候就能夠直接用一個變量來獲取jSlider對象,而後調用setSliderValue方法了,僞碼:

var slider = $.fn.jSlider({ });
slider.setSliderValue(v,function(){});

setSliderValue代碼:

try {
    //validate
    if (typeof v == 'undefined' || v < 0 || v > 1) {
        throw new Error('\'v\' must be a Float variable between 0 and 1.');
    }

    

var s = this;

    

//validate 
    if (typeof s == 'undefined' ||
        typeof s.data == 'undefined' ||
            typeof s.data.bar == 'undefined') {
        throw new Error('You bound the method to an object that is not a slider!');
    }

    $sliderProcess(s, s.data.completed, v 

* s.data.bar.width());

    

if (typeof callback != 'undefined') { callback(v); }
}
catch (e) {
    alert(e.message);
}

這裏一樣調用了全局Function $sliderProcess在設置slider的value值時進行completedbar[width]和slider[left]的更新。因爲此 處進行了異常處理,因此若是end-user在確保setSliderValue被做用於jSlider對象的時候能夠刪除此異常處理代 碼。

【皮膚】
根據jSlider的API咱們能夠更加方便的爲其設定皮膚,爲了讓jSlider更加專業,咱們須要2張圖片:

用來做爲completedbar背景的'bar'和用來做爲slider背景的'slider',ok,咱們更新下樣式:

BlueSkin

因爲在設置樣式時我仍然讓子節點樣式使用了API的默認值,所以在建立jSlider時咱們只須要設置barCssName就好了:
 

var blue = $.fn.jSlider({
    renderTo: '#slidercontainer',
    size: { barWidth: 500, sliderWidth: 10 },
    barCssName: 'bluebar',
    onChanging: function(percentage, e) {
        // code goes here
    }
});

呈現出來的UI:

咱們這樣來設置其值:

//set percentage with a callback function
blue.setSliderValue(0.65, function(percentage) {
    // code goes here
});

【通用性】
固然,咱們不只能夠將jSlider做爲slider使用,有時候它也是一個progressbar:

(代碼我就不貼了,直接在demo裏查看  )

【小結】 
通篇到這裏就結束了,簡單的介紹了一款jQuery插件的開發流程,以及開發中應該注意的細節,那麼在下一篇的文章中我會向你們介紹如何打造一個通用型的 自動完成 插件。

【前言】
jQuery已經被普遍使用,憑藉其簡潔的API,對DOM強大的操控性,易擴展性愈來愈受到web開發人員的喜好,我在社區也發佈了不少的jQuery插件,常常有人詢問一些技巧,所以乾脆寫這麼一篇文章給各位jQuery愛好者,算是拋磚引玉吧。

【基礎】 
a)樣式
很 多人會認爲樣式是個很複雜的東西,須要沉着冷靜的心態加上非凡的審美觀才能設計出賞心悅目的UI,拋開圖片設計不說,其實css也就是那麼些屬 性:position,margin,padding,width,height,left,top,float,border,background…

UI設計的漂亮與否在很大程度上依賴於設計人員對配色的把握和總體效果的協調。舉個簡單的例子,一個簡單的頁面,馬虎的人:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Test Page</title>
</head>
<body>
    jQuery是一個框架!壓縮後有30多k吧。
</body>
</html>


細心的人:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Test Page</title>
    <style type="text/css">
        body
        {
            font-family:'宋體';
            font-size:12px;
            }
    </style>
</head>
<body>
    jQuery是一個框架!壓縮後有30多k吧。
</body>
</html>

專心的人:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Test Page</title>
    <style type="text/css">
        body
        {
            font-family:'Verdana','宋體';
            font-size:12px;
            }
    </style>
</head>
<body>
    jQuery是一個框架!壓縮後有30多k吧。
</body>
</html>


咱們對比一下三者的UI效果:



一目瞭然,或許不少的站點失去關注正是由於這不起眼的font-family,font-size。固然這還只是個簡單的例子,掌握css應該從簡單作起,從基本入手,在實踐中運用並不斷深刻。

b)腳本 
咱們一樣須要對javascript有着深入的理解,對dom, xhr, Regex, call-apply, prototype等都應該有必定的瞭解。

有人會說要這些有啥用啊,對dom的操做其實經過getElementById, getElementsByTagName以及其餘的API均可以輕鬆的完成,這話是沒錯,當思路肯定後,思想纔是重點,一段代碼是精華仍是糟粕很容易就 能夠區分出來,究其緣由仍是取決你本身,舉個簡單的例子,大量的html組裝,路人甲:

var a = new Array(10);
var menu = '';   
for (var i = 0; i < a.length; i++) {
  menu += '<li class="style_' + a[i] + '" >' + a[i] + '</li>';
}


路人乙:

String.prototype.format = function() {
    var args = arguments;
    return this.replace(/{(\d{1})}/g, function() {
        return args[arguments[1]];
    });
};var a = new Array(1,2,3,4,5,6,7,8,9,0);
var m = '<li class="style_{0}" >{0}</li>';for (var i = 0; i < a.length; i++) {
    menu += m.format(a[i]);
}


在實現方式明確的狀況下,優雅高效的代碼顯然更具吸引力。

【實踐】
jQuery開發或使用,更多的靈感是來自實踐,而不是copy||paste(奉行拿來主義的同窗能夠離開了)。

那麼在這裏我會用一個簡單的例子來闡述jQuery插件開發的流程,可否觸類旁通就看各位看官了。

【目的】 

開發一個插件以前咱們須要對本身的目的有一個清醒的認識,有很明確的方向感,那麼這次我做爲示例插件的目的,就是呈現一個用於UI的Slider – 滑動條,常年從事於或暫時專一於win32開發的同窗應該比較瞭解。

草圖

真正動手編碼以前咱們還須要有一個草圖來描述本身插件的「長相」(事件驅動或API封裝的能夠忽略)。
不少的同窗在作UI開發前每每會忙於蒐集各類小圖片(非精通ps或iconworkshop人士),其實漂亮的圖標的確能夠美化咱們的UI,不過我通常的處理方式是編寫易於擴展的css,前期的UI呈現儘可能少使用圖片,多用線條完成。

ok,言歸正卷,那麼個人slider設計草圖是:

 

解釋下下文將用到的幾個詞:
slider: 此部分是做爲拖拽手柄來使用,用戶能夠經過拖拽此部分來更新completed bar的位置。
completed: 此部分做爲bar的內嵌元素,做爲特殊效果來顯示slider與起始點的距離,亦即與slider的value值關聯。
bar: slider的載體,completed的滿值。

思路:
slider做爲手柄提供拖拽功能,做用區域爲bar,拖拽過程當中completed條必須實時更新(長度),影響區域爲slider至bar左端的距離。

【編碼】 

開發jQuery UI/Effect 插件在不少時候都須要與UI交互,所以在呈現上須要提供Html tree來繪製咱們的插件,最終經過js dom來輸出,那麼在繪製簡單的dom結構的時候我會直接用js來完成,不過若是嵌套比較複雜的話,咱們仍是應該先用html來完成,而後轉變成js輸 出。

html tree:

<div class="defaultbar">
  <div class="jquery-completed"> </div>
  <div class="jquery-jslider"> </div>
</div>

deafultbar -> bar
jquery-completed -> completed
jquery-jslider -> slider

前期UI呈現上咱們不使用圖片,儘可能用線條、顏色來完成:

Css

將bar的position屬性設置成relative,以方便子節點的浮動(子節點使用>

那麼咱們能夠看下這個css和html tree產生的UI效果:
 

ok,具有了所需的元素 – slider, completed, bar.

一些規範:

當咱們畫出了UI以後就能夠正式編寫jQuery插件代碼了,不過在着以前咱們還須要對jQuery插件開發的一些規範性有一些瞭解。

1. 使用閉包:

(function($) {
  // Code goes here
})(jQuery);

這是來自jQuery官方的插件開發規範要求,使用這種編寫方式有什麼好處呢?

a) 避免全局依賴。

b) 避免第三方破壞。

c) 兼容jQuery操做符'$'和'jQuery '

咱們知道這段代碼在被解析時會形同以下代碼:

var jq = function($) {
  // Code goes here
}; 
jq(jQuery);

這樣效果就一目瞭然了。

2. 擴展

jQuery提供了2個供用戶擴展的‘基類’ – $.extend和$.fn.extend.

$.extend 用於擴展自身方法,如$.ajax, $.getJSON等,$.fn.extend則是用於擴展jQuery類,包括方法和對jQuery對象的操做。爲了保持jQuery的完整性,我比較 趨向於使用$.fn.extend進行插件開發而儘可能少使用$.extend.

3. 選擇器

jQuery提供了功能強大,併兼容多種css版本的選擇器,不過發現不少同窗在使用選擇器時並未注重效率的問題。 

a) 儘可能使用Id選擇器,jQuery的選擇器使用的API都是基於getElementById或getElementsByTagName,所以能夠知道 效率最高的是Id選擇器,由於jQuery會直接調用getElementById去獲取dom,而經過樣式選擇器獲取jQuery對象時每每會使用 getElementsByTagName去獲取而後篩選。

b) 樣式選擇器應該儘可能明確指定tagName, 若是開發人員使用樣式選擇器來獲取dom,且這些dom屬於同一類型,例如獲取全部className爲jquery的div,那麼咱們應該使用的寫法 是$('div.jquery')而不是$('.jquery'),這樣寫的好處很是明顯,在獲取dom時jQuery會獲取div而後進行篩選,而不是 獲取全部dom再篩選。

c) 避免迭代,不少同窗在使用jQuery獲取指定上下文中的dom時喜歡使用迭代方式,如$('.jquery .child'),獲取className爲jquery的dom下的全部className爲child的節點,其實這樣編寫代碼付出的代價是很是大 的,jQuery會不斷的進行深層遍從來獲取須要的元素,即便確實須要,咱們也應該使用諸如$(selector,context), $('selector1>selector2'), $(selector1).children(selector2), $(selctor1).find(selector2)之類的方式。

開始編碼 

話題有點扯遠,ok,在對UI有了清晰的認識後咱們就可使用js來輸出html了。

咱們使用jSlider來命名這個slider插件(爲了不插件衝突,插件命名時也應十分考究,這裏我就俗一回)。

$.extend($.fn, {
        ///<summary>
        /// apply a slider UI
        ///</summary>
        jSlider: function(setting) {
        }
});

在插件開發中比較標準的方式是將元數據獨立出來並開放API,好比這裏的setting參數傳入值,有時候爲了減小代碼編寫量,我習慣於直接在插件內賦值:

var ps = $.extend({
    renderTo: $(document.body),
    enable: true,
    init;'max',
    size: { barWidth: 200, sliderWidth: 5 },
    barCssName: 'defaultbar',
    completedCssName: 'jquery-completed',
    sliderCssName: 'jquery-jslider',
    sliderHover: 'jquery-jslider-hover',
    onChanging: function() { },
    onChanged: function() { }
}, setting);


規範的作法:

$.fn.jSlider.default = {
    renderTo: $(document.body),
    enable: true,
    init;'max',
    size: { barWidth: 200, sliderWidth: 5 },
    barCssName: 'defaultbar',
    completedCssName: 'jquery-completed',
    sliderCssName: 'jquery-jslider',
    sliderHover: 'jquery-jslider-hover',
    onChanging: function() { },
    onChanged: function() { }
    };

$.extend({},$.fn.jSlider.

default,setting);


ok, 下面描述下我所定義的這些API的做用:
renderTo: jSlider的載體、容器,能夠是一個jQuery對象,也能夠是選擇器。
enable: jSlider插件是否可用,true時end-user可拖拽,不然禁止。
initPosition: jSlider的初始值,‘max’或者‘min’,亦即 slider的value值,1或者0。
size: jSlider的參數,包括2個值barWidth – bar的長度, sliderWidth – slider的長度。
barCssName: bar的樣式名稱,便於end-user自行擴展樣式。
completedCssName: completed的樣式名稱。
sliderCssName: slider的樣式名稱。
sliderHover: slider聚焦時的樣式名稱。
onChanging: slider被拖拽時觸發的事件。
onChanged: slider拖拽結束時觸發的事件。

此時咱們須要將renderTo強制轉換成jQuery對象(兼容使用selector的狀況):

ps.renderTo = (typeof ps.renderTo == 'string' ?
                 $(ps.renderTo) : ps.renderTo);


而後將html tree輸出到render:

/* ———->
html tree:
<div> —->sliderbar
<div>&nbsp;</div>   —-> completed bar
<div>&nbsp;</div>   —-> slider                  
</div>
<———–*/
var sliderbar = $('<div><div>&nbsp;</div><div>&nbsp;</div></div>')
                    .attr('class', ps.barCssName)
                        .css('width', ps.size.barWidth)
                            .appendTo(ps.renderTo);var completedbar = sliderbar.find('div:eq(0)')
                        .attr('class', ps.completedCssName);var slider = sliderbar.find('div:eq(1)')
                .attr('class', ps.sliderCssName)
                    .css('width', ps.size.sliderWidth);

這樣咱們就在UI上直接呈現了Html而且用定製的css進行渲染,分別用sliderbar, completedbar, slider對咱們須要的三個對象進行緩存。

ok, 在呈現了UI後咱們就須要提供方法來實現slider的拖拽,在這以前咱們還須要實現一個方法,就是completedbar的實時更新,即在拖動slider的時候讓completedbar始終填充左側區域:

var bw = sliderbar.width(), sw = slider.width();
//make sure that the slider was displayed in the bar(make a limited)
ps.limited = { min: 0, max: bw - sw };if (typeof window.$sliderProcess == 'undefined') {
    window.$sliderProcess = new Function('obj1', 'obj2', 'left',
                                     'obj1.css(\'left\',left);obj2.css(\'width\',left);');
}
$sliderProcess(slider, completedbar, eval('ps.limited.' + ps.initPosition));

bw,sw用來存儲sliderbar和slider的長度,此處沒有直接使用ps.size裏的值是爲了防止樣式裏的border-width對width形成破壞。

定義一個私用成員limited來存儲slider[left]的最大值和最小值,並在後面直接使用eval('ps.limited.' + ps.initPosition)來獲取,從而避免switch操 做。

同時還需定義一個全局Function用來定位completedbar的填充長度以及slider左側距離,我給其命名爲$sliderProcess。

那麼咱們接下來剩下的工做就是slider的拖拽功能了,那麼在這裏我會用到以前發佈的一款jQuery拖拽插件,並作適量的訂製:

//drag and drop
var slide = {
    drag: function(e) {
        var d = e.data;
        var l = Math.min(Math.max(e.pageX - d.pageX + d.left, ps.limited.min), ps.limited.max);

        $sliderProcess(slider, completedbar, l);
        

//push two parameters: 1st:percentage, 2nd: event
        ps.onChanging(l / ps.limited.max, e);
    },
    drop: function(e) {
        slider.removeClass(ps.sliderHover);
        //push two parameters: 1st:percentage, 2nd: event
        ps.onChanged(parseInt(slider.css('left')) / ps.limited.max, e);

        $().unbind(

'mousemove', slide.drag).unbind('mouseup', slide.drop);
    }
};if (ps.enable) {
    //bind events
    slider.bind('mousedown', function(e) {
        var d = {
            left: parseInt(slider.css('left')),
            pageX: e.pageX
        };
        $(this).addClass(ps.sliderHover);
        $().bind('mousemove', d, slide.drag).bind('mouseup', d, slide.drop);
    });
}

這樣當jSlider enable屬性爲true時,在end-user按下鼠標時綁定mousemove事件,在鼠標彈起時移除,咱們只須要同步更新slider的left 屬性和completedbar的width便可,同時在drag中綁定onChanging方法,在drop中綁定onChanged方法,向這兩個方 法推送的參數相同,1>百分比,即value值,介於0~1,2>event。

那麼至此咱們的jSlider插件就基本成型,向用戶提供了一個可拖拽的slider。

【擴展】 
有的時候用戶卻不是那麼容易知足,因而有人高呼:「我要本身設置value,爲何不提供這個功能?」。

那麼這時咱們就須要爲用戶公開一個方法,用於設置jSlider的value,首先考慮的是做爲方法須要一個做用對象(jSlider),那麼此時我又不 想將做用對象做爲參數傳入,那麼咱們仍是將這個方法做爲插件來開發,咱們將方法命名爲setSliderValue,開放2個參數,v(value值)和 callback(設置完成後的回調函數)。

即:$.fn.setSliderValue(v,callback);

ok,那麼剩下的就是做用對象了,由以前的設計可知,在slider拖動時主要做用於2個對象,slider和completedbar,那麼咱們在jSlider插件末尾加上一段代碼來返回slider對象:

slider.data = { bar: sliderbar, completed: completedbar };
return slider;

這樣咱們在初始化jSlider的時候就能夠直接用一個變量來獲取jSlider對象,而後調用setSliderValue方法了,僞碼:

var slider = $.fn.jSlider({ });
slider.setSliderValue(v,function(){});

setSliderValue代碼:

try {
    //validate
    if (typeof v == 'undefined' || v < 0 || v > 1) {
        throw new Error('\'v\' must be a Float variable between 0 and 1.');
    }

    

var s = this;

    

//validate 
    if (typeof s == 'undefined' ||
        typeof s.data == 'undefined' ||
            typeof s.data.bar == 'undefined') {
        throw new Error('You bound the method to an object that is not a slider!');
    }

    $sliderProcess(s, s.data.completed, v 

* s.data.bar.width());

    

if (typeof callback != 'undefined') { callback(v); }
}
catch (e) {
    alert(e.message);
}

這裏一樣調用了全局Function $sliderProcess在設置slider的value值時進行completedbar[width]和slider[left]的更新。因爲此 處進行了異常處理,因此若是end-user在確保setSliderValue被做用於jSlider對象的時候能夠刪除此異常處理代 碼。

【皮膚】
根據jSlider的API咱們能夠更加方便的爲其設定皮膚,爲了讓jSlider更加專業,咱們須要2張圖片:

用來做爲completedbar背景的'bar'和用來做爲slider背景的'slider',ok,咱們更新下樣式:

BlueSkin

因爲在設置樣式時我仍然讓子節點樣式使用了API的默認值,所以在建立jSlider時咱們只須要設置barCssName就好了:
 

var blue = $.fn.jSlider({
    renderTo: '#slidercontainer',
    size: { barWidth: 500, sliderWidth: 10 },
    barCssName: 'bluebar',
    onChanging: function(percentage, e) {
        // code goes here
    }
});

呈現出來的UI:

咱們這樣來設置其值:

//set percentage with a callback function
blue.setSliderValue(0.65, function(percentage) {
    // code goes here
});

【通用性】
固然,咱們不只能夠將jSlider做爲slider使用,有時候它也是一個progressbar:

(代碼我就不貼了,直接在demo裏查看  )

【小結】  通篇到這裏就結束了,簡單的介紹了一款jQuery插件的開發流程,以及開發中應該注意的細節,那麼在下一篇的文章中我會向你們介紹如何打造一個通用型的 自動完成 插件。

相關文章
相關標籤/搜索