自己寫jquery插件之模版插件高級篇(一)


需求場景

最近項目改版中,發現很多地方有這樣一個操作(見下圖gif動畫演示),很多地方都有用到。這里不討論它的用戶體驗怎么樣。

僅僅是從復用的角度,如果每個頁面都去寫text和select元素,兩個button按鈕,增加add和delete對應的js函數,無疑大大增加了工作量和維護成本。

select有預設值的情況:

下面就開始動手把這4個html元素做成一個JQuery插件。

jquery插件結構

如果你是零基礎,請參考Jquery官網對jquery plugin的介紹:http://learn.jquery.com/plugins/

整個插件做好后是一個js文件,我們首先來看下它的整體結構,如下圖:

調用時的代碼(無參):

$(".demo1").dlpcustomSelect();

調用時的代碼(有參):

$(".demo1").dlpcustomSelect({
      addButtonText:'Add',
      delButtonText:'>>'
});

前台HTML:

<select class="demo1"></select>

這樣就把插件定義的html元素全部渲染出來了,插件自帶了相關js函數和功能。代碼維護起來非常方便。

下面我們開始這個Jquery插件的制作過程:

一. 定義插件結構,插件名稱,默認值和構造函數

1.插件結構,名稱,默認值

新建dlpcustomselect.js文件后,我們首先書寫這樣的代碼:

;(function ($, window, document, undefined) {
  //Author:HANGWEI
  //Create the defaults once
  var pluginName = 'dlpcustomSelect',
    defaults = {
      addButtonEnabled : true,
      addButtonText: 'Add',
      delButtonText:'Delete'
    };
//... other code ...

// A really lightweight plugin wrapper around the constructor,
  // preventing against multiple instantiations
  $.fn[ pluginName ] = function (options) {
    var args = arguments;

    // Is the first parameter an object (options), or was omitted, instantiate a new instance of the plugin.
    if (options === undefined || typeof options === 'object') {
      return this.each(function () {
        // If this is not a select
        if (!$(this).is('select')) {
          $(this).find('select').each(function(index, item) {
            // For each nested select, instantiate the dlp custom select
            $(item).dlpcustomSelect(options);//注意此處的插件名稱
          });
        } else if (!$.data(this, 'plugin_' + pluginName)) {
          // Only allow the plugin to be instantiated once so we check that the element has no plugin instantiation yet

          // if it has no instance, create a new one, pass options to our plugin constructor,
          // and store the plugin instance in the elements jQuery data object.
          $.data(this, 'plugin_' + pluginName, new DlpCustomSelect(this, options));//注意此處插件的構造函數
        }
      });
      // If the first parameter is a string and it doesn't start with an underscore or "contains" the `init`-function,
      // treat this as a call to a public method.
    } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {

      // Cache the method call to make it possible to return a value
      var returns;

      this.each(function () {
        var instance = $.data(this, 'plugin_' + pluginName);
        // Tests that there's already a plugin-instance and checks that the requested public method exists
        if (instance instanceof DlpCustomSelect && typeof instance[options] === 'function') {//注意此處插件構造函數名 // Call the method of our plugin instance, and pass it the supplied arguments.
          returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1));
        }
      });

      // If the earlier cached method gives a value back return the value,
      // otherwise return this to preserve chainability.
      return returns !== undefined ? returns : this;
    }

  };

})(jQuery, window, document);

 在上述代碼中,pluginName是插件名稱,defaults規定了插件的三個參數及其默認值;

 $.fn[pluginName]=function(options){};函數的功能,如代碼注釋所說,阻止多個插件實例被創建。

 ;(function ($, window, document, undefined) {  這句代碼的詳細解釋請參考 這里

2. 構造函數

  // The actual plugin constructor
  function DlpCustomSelect(element, options) {
    this.element = $(element);
    // jQuery has an extend method which merges the contents of two or
    // more objects, storing the result in the first object. The first object
    // is generally empty as we don't want to alter the default options for
    // future instances of the plugin
    this.settings = $.extend({}, defaults, options);
    this._defaults = defaults;
    this._name = pluginName;
    this.init();
  }

構造函數用於初始化和參數定義,如無特殊需求, 可參考上述寫法來定義。

二. 編寫插件核心部分代碼

下面我們開始章節一代碼結構中: other code 的部分

1. 構造函數名.prototype={...};

  1 DlpCustomSelect.prototype = {
  2     init: function () {
  3       // Add the custom HTML template
  4       this.container = $('' +
  5       '<div class="dlpcustomselect-container">' +
  6         '<table class="box1">' +
  7         ' <tr>' +
  8         '   <td><input class="waitAddValue" type="text" size="48" /></td>' +
  9         '   <td><input class="btn-pull-buttom" type="button" /></td>' +
 10         ' </tr>' +
 11         ' <tr>' +
 12         '   <td><select style="width: 265px;height: 100px" multiple="multiple"></select></td>' +
 13         '   <td><input class="btn-delete-buttom" type="button" /></td>' +
 14         ' </tr>' +
 15         '</table>'+
 16       '</div>')
 17         .insertBefore(this.element);
 18 
 19       // Cache the inner elements
 20       this.elements = {
 21         originalSelect: this.element,
 22         box1: $('.box1', this.container),
 23         filterInput1: $('.box1 .waitAddValue', this.container),
 24         select1: $('.box1 select', this.container),
 25         addButton: $('.box1 .btn-pull-buttom', this.container),
 26         deleteButton: $('.box1 .btn-delete-buttom', this.container)
 27       };
 28 
 29       // Set select IDs
 30       this.originalSelectName = this.element.attr('name') || '';
 31       var select1Id = 'dlpcustomselect-list_' + this.originalSelectName;
 32       this.elements.select1.attr('id', select1Id);
 33 
 34       // Apply all settings
 35       this.setAddButtonEnabled(this.settings.addButtonEnabled);
 36       this.setAddButtonText(this.settings.addButtonText);
 37       this.setDelButtonText(this.settings.delButtonText);
 38 
 39       //updateSelectionStates(this);
 40       // Hide the original select
 41       this.element.hide();
 42 
 43       bindEvents(this);
 44       refreshSelects(this);
 45 
 46       return this.element;
 47     },
 48     setAddButtonEnabled: function(value, refresh) {
 49       this.settings.addButtonEnabled = value;
 50       if (value) {
 51         this.container.find('.btn-pull-buttom').removeAttr("disabled");
 52       } else {
 53         this.container.find('.btn-pull-buttom').attr("disabled","disabled");
 54       }
 55       if (refresh) {
 56         //refreshSelects(this);
 57       }
 58       return this.element;
 59     },
 60     setAddButtonText: function(value, refresh) {
 61       this.settings.addButtonText = value;
 62       if (value) {
 63         this.elements.addButton.show().val(value);
 64         //if upper code type doesn't work,use this code.
 65         //this.container.find('.btn-pull-buttom').show().val(value);
 66       } else {
 67         this.elements.addButton.hide().val(value);
 68         //if upper code type doesn't work,use this code.
 69         //this.container.find('.btn-pull-buttom').hide().val(value);
 70       }
 71       if (refresh) {
 72         //refreshSelects(this);
 73       }
 74       return this.element;
 75     },
 76     setDelButtonText: function(value, refresh) {
 77       this.settings.delButtonText = value;
 78       if (value) {
 79         this.elements.deleteButton.show().val(value);
 80       } else {
 81         this.elements.deleteButton.hide().val(value);
 82       }
 83       if (refresh) {
 84         //refreshSelects(this);
 85       }
 86       return this.element;
 87     },
 88     getCustomData: function(){
 89       var terms = new Array();
 90       this.container.find('.box1 select option').each(function(index, item) {
 91         terms.push(item['value']);
 92       });
 93       return terms;
 94     },
 95     getContainer: function() {
 96       return this.container;
 97     },
 98     destroy: function() {
 99       this.container.remove();
100       this.element.show();
101       $.data(this, 'plugin_' + pluginName, null);
102       return this.element;
103     }
104   };
View Code

init:function(){...}  需要實現的init函數,這里我們用來創建html模板、應用所有的設置、調用綁定事件。

方法 refreshSelects(this)用來將前台select中的元素(如果有的話)copy到插件中。

方法 getCustomData用來返回插件的值

這里的設計思路是:隱藏你在前台寫的select元素,返回插件模板中的自定義html串。另外,如果前台select中有option元素,則同步copy到插件中。

三. 綁定插件按鈕事件和書寫自定義功能函數

//bind events for button
  function bindEvents(dlpCustomSelect) {
    dlpCustomSelect.elements.addButton.on('click', function() {
      addOption(dlpCustomSelect);
    });
    dlpCustomSelect.elements.deleteButton.on('click', function() {
      deleteOption(dlpCustomSelect);
    });
      //backup method.
      /*
      $(document).on('click', '.box1 .btn-pull-buttom', function() {
          addOption(dlpCustomSelect);
      });
      */
  }

如以上代碼所示,綁定插件的兩個按鈕的事件。其中addOption和deleteOption函數具體實現這里不再詳細闡述。 

根據項目實際需要,增加自定義綁定事件和函數。

四. 完成並測試

調用插件:

$(".demo1").dlpcustomSelect({
                addButtonText:'Add',
                delButtonText:'>>'
            });

不更改參數值,直接調用(使用默認參數值):

$(".demo2").dlpcustomSelect();

獲取插件中的值:$(".demo1").dlpcustomSelect('getCustomData')

demo下載

總結

本插件的實現大量參考了國外jquery插件制作的通用做法。希望本篇文章能起到拋磚引玉的作用,能引導開發人員自己動手寫jquery插件。

本來想掛在github上,但鑒於這個插件的功能很少,就不費周章了。需要的直接在本篇文章下載吧。

另外本人水平有限,如有錯誤之處還請各位批評指正。

希望本文對你有幫助。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM