需求场景

最近项目改版中,发现很多地方有这样一个操作(见下图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={...};

 DlpCustomSelect.prototype = {
init: function () {
// Add the custom HTML template
this.container = $('' +
'<div class="dlpcustomselect-container">' +
'<table class="box1">' +
' <tr>' +
' <td><input class="waitAddValue" type="text" size="48" /></td>' +
' <td><input class="btn-pull-buttom" type="button" /></td>' +
' </tr>' +
' <tr>' +
' <td><select style="width: 265px;height: 100px" multiple="multiple"></select></td>' +
' <td><input class="btn-delete-buttom" type="button" /></td>' +
' </tr>' +
'</table>'+
'</div>')
.insertBefore(this.element); // Cache the inner elements
this.elements = {
originalSelect: this.element,
box1: $('.box1', this.container),
filterInput1: $('.box1 .waitAddValue', this.container),
select1: $('.box1 select', this.container),
addButton: $('.box1 .btn-pull-buttom', this.container),
deleteButton: $('.box1 .btn-delete-buttom', this.container)
}; // Set select IDs
this.originalSelectName = this.element.attr('name') || '';
var select1Id = 'dlpcustomselect-list_' + this.originalSelectName;
this.elements.select1.attr('id', select1Id); // Apply all settings
this.setAddButtonEnabled(this.settings.addButtonEnabled);
this.setAddButtonText(this.settings.addButtonText);
this.setDelButtonText(this.settings.delButtonText); //updateSelectionStates(this);
// Hide the original select
this.element.hide(); bindEvents(this);
refreshSelects(this); return this.element;
},
setAddButtonEnabled: function(value, refresh) {
this.settings.addButtonEnabled = value;
if (value) {
this.container.find('.btn-pull-buttom').removeAttr("disabled");
} else {
this.container.find('.btn-pull-buttom').attr("disabled","disabled");
}
if (refresh) {
//refreshSelects(this);
}
return this.element;
},
setAddButtonText: function(value, refresh) {
this.settings.addButtonText = value;
if (value) {
this.elements.addButton.show().val(value);
//if upper code type doesn't work,use this code.
//this.container.find('.btn-pull-buttom').show().val(value);
} else {
this.elements.addButton.hide().val(value);
//if upper code type doesn't work,use this code.
//this.container.find('.btn-pull-buttom').hide().val(value);
}
if (refresh) {
//refreshSelects(this);
}
return this.element;
},
setDelButtonText: function(value, refresh) {
this.settings.delButtonText = value;
if (value) {
this.elements.deleteButton.show().val(value);
} else {
this.elements.deleteButton.hide().val(value);
}
if (refresh) {
//refreshSelects(this);
}
return this.element;
},
getCustomData: function(){
var terms = new Array();
this.container.find('.box1 select option').each(function(index, item) {
terms.push(item['value']);
});
return terms;
},
getContainer: function() {
return this.container;
},
destroy: function() {
this.container.remove();
this.element.show();
$.data(this, 'plugin_' + pluginName, null);
return this.element;
}
};

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上,但鉴于这个插件的功能很少,就不费周章了。需要的直接在本篇文章下载吧。

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

希望本文对你有帮助。

自己写jquery插件之模版插件高级篇(一)的更多相关文章

  1. 自写 jQuery 大幅弹窗广告插件(不喜勿拍)

    最近写了做的两个项目都要做几乎同一件事,在首页弹出一个广告.本来是想在网上找一个的,找了几个,花了时间但都不怎么满意,尼玛呀,坑爹呀…… 最后一想,干脆自己动手了. 第一次写,在网上找一些例子来看. ...

  2. 锋利的jQuery--编写jQuery插件(读书笔记五)[完结篇]

    1.表单验证插件Validation   2.表单插件Form   3.动态事件绑定插件livequery 可以为后来的元素绑定事件   类似于jQuery中的live()方法     4.jQuer ...

  3. 什么?你还不会写JQuery 插件

    前言 如今做web开发,jquery 几乎是必不可少的,就连vs神器在2010版本开始将Jquery 及ui 内置web项目里了.至于使用jquery好处这里就不再赘述了,用过的都知道.今天我们来讨论 ...

  4. 写JQuery 插件 什么?你还不会写JQuery 插件

    http://www.cnblogs.com/Leo_wl/p/3409083.html 前言 如今做web开发,jquery 几乎是必不可少的,就连vs神器在2010版本开始将Jquery 及ui ...

  5. 第一次写jquery插件,来个countdown计时器吧

    之前同学做个购物商城秒杀活动需要计时器的功能,在用jquery提供的countdown插件时,一直报错,貌似还需要依赖除jquery之外的其他插件,搞了半天也没搞成功,就叫我帮忙写个.然而我并没有写过 ...

  6. 写jQuery插件

    如今做web开发,jquery 几乎是必不可少的,就连vs神器在2010版本开始将Jquery 及ui 内置web项目里了.至于使用jquery好处这里就不再赘述了,用过的都知道.今天我们来讨论下jq ...

  7. 写JQuery插件的基本知识

    普及JQuery知识 知识1:用JQuery写插件时,最核心的方法有如下两个: 复制代码 代码如下: $.extend(object) 可以理解为JQuery 添加一个静态方法. $.fn.exten ...

  8. 教你写Jquery插件

    最近很多网友说 jQuery插件是什么啊?怎么写的啊?我不会写啊? 一大堆的问题一时都不知道怎么回答他们,个人认为是网友们把问题复杂化了. 其实就是把一些常用.实用.通用的功能封装起来而以,简单的来讲 ...

  9. [原创作品]手把手教你怎么写jQuery插件

    这次随笔,向大家介绍如何编写jQuery插件.啰嗦一下,很希望各位IT界的‘攻城狮’们能和大家一起分享,一起成长.点击左边我头像下边的“加入qq群”,一起分享,一起交流,当然,可以一起吹水.哈,不废话 ...

随机推荐

  1. vue入门学习(基础篇)

    vue入门学习总结: vue的一个组件包括三部分:template.style.script. vue的数据在data中定义使用. 数据渲染指令:v-text.v-html.{{}}. 隐藏未编译的标 ...

  2. AJAX操作数据

    本文使用AJAX访问数据库文件,并显示在网页中.另外还有AJAX对数据库的删除操作,网页不加载,只刷新数据. 随意使用数据库中的一张表: 使用AJAX显示表中内容,首先打入body代码: <h1 ...

  3. C#——传值参数(2)

    //我的C#是跟着猛哥(刘铁猛)(算是我的正式老师)<C#语言入门详解>学习的,微信上猛哥也给我讲解了一些不懂得地方,对于我来说简直是一笔巨额财富,难得良师! 这次与大家共同学习C#中的 ...

  4. 设计模式C#合集--单例模式

    单例模式 代码: 第一种: private static Singleton singleton = null; private Singleton() { } public static Singl ...

  5. ReactiveCocoa代码实践之-UI组件的RAC信号操作

    上一节是自己对网络层的一些重构,本节是自己一些代码小实践做出的一些demo程序,基本涵盖大多数UI控件操作. 一.用UISlider实现调色板 假设我们现在做一个demo,上面有一个View用来展示颜 ...

  6. HTML5 程序设计 - 使用HTML5 Canvas API

    请你跟着本篇示例代码实现每个示例,30分钟后,你会高喊:“HTML5 Canvas?!在哥面前,那都不是事儿!” 呵呵.不要被滚动条吓到,很多都是代码和图片.我没有分开写,不过上面给大家提供了目录,方 ...

  7. mysql 赋予用户权限

    # 赋予权限MySQL> grant 权限参数 on 数据库名称.表名称 to 用户名@用户地址 identified by '用户密码'; # 立即生效权限MySQL> flush pr ...

  8. TFS 生成发布代理

    下载Agent 后,执行配置命令     参考 安装TFS(2015)工作组模式代理服务器(Agent)

  9. 【python之路4】循环语句之while

    1.while 循环语句 #!/usr/bin/env python # -*- coding:utf-8 -*- import time bol = True while bol: print '1 ...

  10. Concurrency

    <Concurrency>:http://docs.oracle.com/javase/tutorial/essential/concurrency/index.html <Java ...