寫一個 jQuery 插件

第一次寫jquery插件,在這裏作一個記錄和積累。全部文章均同步到個人博客javascript

寫jQuery插件的目的

主要是對一些重複使用率高的一系列方法或函數作封裝,可以提升開發的效率,也方便後期維護html

寫插件前須要知道的預備知識

jQuery插件有哪幾種類型?

  1. 封裝對象方法的插件(對象級別)java

    這類插件是最多見的一種,即將對象方法進行封裝,而後經過選擇器獲取的jQuery對象進行操做。
    用法:$('#id').myPlugin()jquery

  2. 封裝全局函數的插件(類級別)git

    即將獨立的函數加到jquery命名空間下, 拓展jQuery類,典型例子$.ajax()
    用法:$.myPlugin()github

jQuery插件中的閉包

常見的jQuery插件形式以下:ajax

//爲了更好的兼容性,開始有個分號
;(function ($) {
    /*你的插件代碼*/
})(jQuery);

利用閉包的特性,避免內部變量影響全局空間,經過形參$將jQuery傳遞給匿名函數,在插件內部就可使用$做爲jQuery的別名。api

jQuery插件的機制

//擴展第一種類型(即對象級別)的插件
jQuery.fn.extend()
//擴展第二種類型(即類級別)的插件
jQuery.extend()

extend()方法接受一個Object類型的參數,key值爲函數名或方法名,value值爲函數主體。閉包

//給jQuery對象添加方法,就是對jQuery.prototype擴展,給jQuery類添加成員方法
$.fn.extend({ 
    getInputText: function(){ 
        $(this).click(function(){ 
            alert($(this).val()); 
        }); 
    } 
});
//$("#username").getInputText();

//給jQuery類擴展,至關於給jQuery添加靜態方法
$.extend({
  add: function(a, b){return a + b;}
});
// $.add(1, 2); //return 3

除了能夠擴展jQuery對象,$.extend(default, options)還能夠擴展Object對象,用傳入的參數options覆蓋默認值default。app

function myPlugin(options) {
    var defaults = {
        color: 'blue',
        width: '100'
    };
    options = $.extend(defaults, options);
}

//myPlugin({color: 'white'});
//myPlugin({color: 'white', width: '200'});
//myPlugin();

須要注意的問題

  • 插件名推薦命名爲jquery.插件名.js,好比jquery.myPlugin.js

  • 插件內部this的指向爲將要執行的jquery對象,而在其餘包含callback的jQuery函數裏,this指向原生DOM元素。

    (function($) {
        $.fn.m​​yPlugin = function () {
    
            //此處沒有必要將this包在$號中如$(this),由於this已是一個jQuery對象。
            //$(this)等同於 $($('#element'));
    
            this.fadeIn('normal', function () {
    
                //此處callback函數中this關鍵字表明一個DOM元素
    
            });
    
        };
    })(jQuery);
  • 用this.each對全部元素進行遍歷,同時爲了保持插件的鏈式調用,確保插件返回this關鍵字

    (function($) {
        $.fn.m​​yPlugin = function () {  
           return this.each(function () {
    
                //此處是你的插件代碼
    
            });
    
        };
    })(jQuery);
  • 保護好默認參數

回顧上面講$.extend(default, options)時舉的例子

```
function myPlugin(options) {
    var defaults = {
        color: 'blue',
        width: '100'
    };
    options = $.extend(defaults, options);
}
```

這種寫法很差,調用extend時會改變defaults的值,defaults做爲插件默認值應維持原狀,若後續想再使用默認值,會發現它已被用戶傳來的值所更改。
因此更好的寫法是把一個新的空對象做爲extend的第一個參數,接下來是defaults和options,那麼全部值合併後保存到了這個空對象上,保護了默認值。

function myPlugin(options) {
    var defaults = {
        color: 'blue',
        width: '100'
    };
    options = $.extend({}, defaults, options);
}

動手編寫一個jQuery插件

以分頁插件做爲練習,體會了上面的知識點,部分地方還有待優化

首先是HTML結構

//要插入頁碼的容器
<div id="pager"></div>
<p class="page-text"></p>

CSS結構

* {margin:0;padding: 0;}
ul {list-style: none;}

.page {height:40px;overflow: hidden;margin-top: 20px;}
.page li {display: inline-block;*display: inline;*zoom:1;border: 1px solid #CCC;background-color: #FFF;margin-right: 5px;padding: 5px 8px;cursor: pointer;}
.page li:hover {border:1px solid #1B4CA6;background-color: #BBD1F9;}
.page li.current {border:1px solid #1B4CA6;background-color: #BBD1F9;}
.page li.disable {border:1px solid #EEE;color:#999;cursor: auto;background-color: #FFF;}
.page-text {margin-top: 10px;}
.page-text strong {color: #78C6E2;margin-left: 3px;margin-right: 3px;}

js的結構

;(function($) {

    var defaults = {
        pagecurrent: 1,   //當前頁碼
        pagecount:1,      //頁碼總數
        first_text: '首頁',  //首頁按鈕的文字可自定義
        prev_text: '上一頁', //上一頁按鈕的文字可自定義
        next_text: '下一頁', //下一頁按鈕的文字可自定義
        last_text: '尾頁',  //尾頁按鈕的文字可自定義
        max_per_page: 10 //每屏最多顯示多少個頁碼
    };

    $.fn.pager = function(options) {
        var options = $.extend({}, defaults, options);

        return this.each(function() {
            $(this).empty().append(renderPage(options));
        });
    }

    function renderPage(opts) {
        var pagecurrent = parseInt(opts.pagecurrent);
        var pagecount = parseInt(opts.pagecount);
        var btncallback = opts.btncallback;
        var max_per_page = parseInt(opts.max_per_page);
        var first_text = opts.first_text;
        var prev_text = opts.prev_text;
        var next_text = opts.next_text;
        var last_text = opts.last_text;
        //頁碼wrap
        var pageWrap = $('<ul class="page"></ul>');
        //添加第一頁和上一頁按鈕
        pageWrap.append(renderBtn('first', first_text, pagecurrent, pagecount, btncallback))
        .append(renderBtn('prev',prev_text, pagecurrent, pagecount, btncallback));

        //控制一屏最多顯示n條頁碼
        var startNum = 1;
        var endNum = max_per_page;
        var point = Math.ceil((endNum - startNum) / 2);

        if (pagecurrent > point) {
            startNum = pagecurrent - point;
            endNum = pagecurrent + point;
        }

        if (endNum > pagecount) {
            startNum = pagecount - max_per_page + 1;
            endNum = pagecount;
        }

        if (startNum < 1) {
            startNum = 1;
        }
        //渲染頁碼列表
        for (var pagenumber = startNum; pagenumber <= endNum; pagenumber++) {
            var pagebtn = $('<li>'+ pagenumber +'</li>');
            if (pagenumber == pagecurrent) {
                pagebtn.addClass('current');
            }
            else {
                pagebtn.click(function() {
                    btncallback(this.innerHTML);
                });
            }
            pageWrap.append(pagebtn);
        }

        //渲染下一頁和尾頁按鈕
        pageWrap.append(renderBtn('next', next_text, pagecurrent, pagecount, btncallback))
        .append(renderBtn('last', last_text, pagecurrent, pagecount, btncallback));

        return pageWrap;
    }
    //首頁,上一頁,下一頁,尾頁按鈕的方法
    function renderBtn(btntype, btntext, pagecurrent, pagecount, btncallback) {
        var button = $('<li>'+ btntext +'</li>');

        var destPage = 1;

        switch (btntype) {
            case 'first':
                destPage = 1;
                break;
            case 'prev':
                destPage = pagecurrent - 1;
                break;
            case 'next':
                destPage = pagecurrent + 1;
                break;
            case 'last':
                destPage = pagecount;
        }

        if (btntype == 'first' || btntype == 'prev') {
            if (pagecurrent <= 1) {
                button.addClass('disable');
            }
            else {
                button.click(function() {
                    btncallback(destPage);
                });
            }
        }
        else {
            if (pagecurrent >= pagecount) {
                button.addClass('disable');
            }
            else {
                button.click(function() {
                    btncallback(destPage);
                });
            }
        }

        return button;
    }

 })(jQuery);

調用

//Google的須要翻一下牆,你懂的--
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
<script src="jquery.pager.js" type="text/javascript"></script>


<script type="text/javascript">
        $(function(){
            $('#pager').pager({
                pagecurrent:1,
                pagecount:20,
                btncallback:pageClickCallback ,
                //first_text: 'first'
            });

        });
        pageClickCallback = function(pageclickednumber){
            $('#pager').pager({
                pagecurrent:pageclickednumber,
                pagecount:20,
                btncallback:PageClick,
                //first_text: 'first'
            });
            $('.page-text').html('當前是第<strong>'+pageclickednumber+'</strong>頁');
        }
</script>

顯示結果

pager分頁

查看 demo

相關文章
相關標籤/搜索