你的位置:首页 > Java教程

[Java教程]自己写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 >' + 6     '<table >' + 7     ' <tr>' + 8     '  <td><input type="text" size="48" /></td>' + 9     '  <td><input type="button" /></td>' + 10     ' </tr>' + 11     ' <tr>' + 12     '  <td><select multiple="multiple"></select></td>' + 13     '  <td><input 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上,但鉴于这个插件的功能很少,就不费周章了。需要的直接在本篇文章下载吧。

另外本人水平有限,如有错误之处还请各位批评指正。

希望本文对你有帮助。