JS组件系列——封装自己的JS组件,你也可以
前言:之前分享了那么多bootstrap组件的使用经验,这篇博主打算研究下JS组件的扩展和封装,我们来感受下JQuery为我们提供$.Extend的神奇,看看我们怎么自定义自己的组件,比如我们想扩展一个$("#id").MyJsControl({})做我们自己的组件,我们该如何去做呢,别急,我们慢慢来看看过程。
一、扩展已经存在的组件
1、需求背景
很多时候,我们使用jquery.ajax的方式向后台发送请求,型如
$.ajax({
type: "post",
url: "/User/Edit",
data: { data: JSON.stringify(postdata) },
success: function (data, status) {
if (status == "success") {
toastr.success('提交数据成功');
$("#tb_aaa").bootstrapTable('refresh');
}
},
error: function (e) {
},
complete: function () {
}
});
这种代码太常见了,这个时候我们有这样一个需求:在自己调用ajax请求的时候,我们不想每次都写error:function(e){}这种代码,但是我们又想让它每次都将ajax的错误信息输出到浏览器让用户能够看到。怎么办呢?
2、实现原理
要想实现以上效果其实并不难,我们可以将$.ajax({})封装一层,在封装的公共方法里面定义error对应的事件即可。确实,这样能达到我们的要求,但是并不完美,原因很简单:1)在jquery的基础上面再封装一层,效率不够高;2)需要改变调用者的习惯,每次调用ajax的时候需要按照我们定义的方法的规则来写,而不能直接用原生的$.ajax({})这种写法,这是我们不太想看到。
既然如此,那我们如何做到既不封装控件,又能达到以上要求呢?答案就是通过我们的$.extend去扩展原生的jquery.ajax。
其实实现起来也并不难,通过以下一段代码就能达到我们的要求。
(function ($) {
//1.得到$.ajax的对象
var _ajax = $.ajax;
$.ajax = function (options) {
//2.每次调用发送ajax请求的时候定义默认的error处理方法
var fn = {
error: function (XMLHttpRequest, textStatus, errorThrown) {
toastr.error(XMLHttpRequest.responseText, '错误消息', { closeButton: true, timeOut: 0, positionClass: 'toast-top-full-width' });
},
success: function (data, textStatus) { },
beforeSend: function (XHR) { },
complete: function (XHR, TS) { }
}
//3.如果在调用的时候写了error的处理方法,就不用默认的
if (options.error) {
fn.error = options.error;
}
if (options.success) {
fn.success = options.success;
}
if (options.beforeSend) {
fn.beforeSend = options.beforeSend;
}
if (options.complete) {
fn.complete = options.complete;
}
//4.扩展原生的$.ajax方法,返回最新的参数
var _options = $.extend(options, {
error: function (XMLHttpRequest, textStatus, errorThrown) {
fn.error(XMLHttpRequest, textStatus, errorThrown);
},
success: function (data, textStatus) {
fn.success(data, textStatus);
},
beforeSend: function (XHR) {
fn.beforeSend(XHR);
},
complete: function (XHR, TS) {
fn.complete(XHR, TS);
}
});
//5.将最新的参数传回ajax对象
_ajax(_options);
};
})(jQuery);
如果没接触过jquery里面$.extend这个方法的童鞋可能看不懂以上是什么意思。好,我们首先来看看jquery API对$.extend()方法是作何解释的。

什么意思呢?我们来看官方的两个例子就知道了
栗子一:
var settings = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
$.extend(settings, options);
结果:
settings == { validate: true, limit: 5, name: "bar" }
栗子二:
var empty = {};
var defaults = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
var settings = $.extend(empty, defaults, options);
结果:
settings == { validate: true, limit: 5, name: "bar" }
empty == { validate: true, limit: 5, name: "bar" }
以上的两个简单例子就说明extend()方法作用就是合并另个对象,有相同的则覆盖,没有相同的则添加。就是这么简单。
了解了$.extend()的作用,我们就能大概看懂上面那个扩展jquery.ajax的实现了吧。主要的步骤分为:
1)定义默认的error处理方法。
var fn = {
error: function (XMLHttpRequest, textStatus, errorThrown) {
toastr.error(XMLHttpRequest.responseText, '错误消息', { closeButton: true, timeOut: 0, positionClass: 'toast-top-full-width' });
},
success: function (data, textStatus) { },
beforeSend: function (XHR) { },
complete: function (XHR, TS) { }
}
2)判断用户在调用$.ajax({})的时候是否自定了error:function(){},如果定义过,则使用用户定义的,反之则用默认的error处理方法。
3)使用$.extend()将error默认处理方法传入$.ajax()的参数中。我们看options参数时包含$.ajax()方法里面所有的参数的,然后用默认的fn去扩展它即可。
通过以上三步就能够实现对$.ajax()方法里面error默认处理方法。这样扩展,对于我们使用者来说完全感觉不到变化,我们仍然可以$.ajax({});这样去发送ajax请求,如果没有特殊情况,不用写error处理方法。
3、组件扩展的意义
使用组件扩展,能够帮助我们在原有组件上面增加一些和我们系统业务相关的处理需求,而在使用时,还是和使用原生组件一样去调用,免去了在组件上面再封装一层的臃肿。
二、扩展自己组件
上面通过$.extend()方法扩展了$.ajax()的error事件处理方法。下面我们来封装一个自己的组件试试,功能很简单,但比较有说明性。我们就以select这个组件为例,很多情况下,我们的select里面的option都是需要从数据库里面取数据的,所以一般的做法就是发送一个ajax请求,然后在success方法里面拼html。现在我们就封装一个select远程取数据的方法。
1、代码实现以及使用示例
先上干货吧,将写好的整出来:
(function ($) {
//1.定义jquery的扩展方法combobox
$.fn.combobox = function (options, param) {
if (typeof options == 'string') {
return $.fn.combobox.methods[options](this, param);
}
//2.将调用时候传过来的参数和default参数合并
options = $.extend({}, $.fn.combobox.defaults, options || {});
//3.添加默认值
var target = $(this);
target.attr('valuefield', options.valueField);
target.attr('textfield', options.textField);
target.empty();
var option = $('<option></option>');
option.attr('value', '');
option.text(options.placeholder);
target.append(option);
//4.判断用户传过来的参数列表里面是否包含数据data数据集,如果包含,不用发ajax从后台取,否则否送ajax从后台取数据
if (options.data) {
init(target, options.data);
}
else {
//var param = {};
options.onBeforeLoad.call(target, options.param);
if (!options.url) return;
$.getJSON(options.url, options.param, function (data) {
init(target, data);
});
}
function init(target, data) {
$.each(data, function (i, item) {
var option = $('<option></option>');
option.attr('value', item[options.valueField]);
option.text(item[options.textField]);
target.append(option);
});
options.onLoadSuccess.call(target);
}
target.unbind("change");
target.on("change", function (e) {
if (options.onChange)
return options.onChange(target.val());
});
}
//5.如果传过来的是字符串,代表调用方法。
$.fn.combobox.methods = {
getValue: function (jq) {
return jq.val();
},
setValue: function (jq, param) {
jq.val(param);
},
load: function (jq, url) {
$.getJSON(url, function (data) {
jq.empty();
var option = $('<option></option>');
option.attr('value', '');
option.text('请选择');
jq.append(option);
$.each(data, function (i, item) {
var option = $('<option></option>');
option.attr('value', item[jq.attr('valuefield')]);
option.text(item[jq.attr('textfield')]);
jq.append(option);
});
});
}
};
//6.默认参数列表
$.fn.combobox.defaults = {
url: null,
param: null,
data: null,
valueField: 'value',
textField: 'text',
placeholder: '请选择',
onBeforeLoad: function (param) { },
onLoadSuccess: function () { },
onChange: function (value) { }
};
})(jQuery);
先来看看我们自定义组件如何使用:
用法一:通过URL远程取数据并初始化
首先定义一个空的select
<select id="sel_search_plant" class="form-control"></select>
然后初始化它
$(function(){
$('#sel_search_plant').combobox({
url: '/apiaction/Plant/Find',
valueField: 'TM_PLANT_ID',
textField: 'NAME_C'
});
})
参数很简单,就不一一介绍了。很简单有木有~~
用法二:取值和设置
var strSelectedValue = $('#sel_search_plant').combobox("getValue");
$('#sel_search_plant').combobox("setValue", "aaa");
其实对于简单的select标签,博主觉得这里的getValu和SetValue意义不大,因为直接通过$('#sel_search_plant').val()就能解决的事,何必要再封一层。这里仅仅是做演示,试想,如果是封装成类似select2或者multiselect这种组件,getValue和setValue的意义就有了,你觉得呢?
2、代码详细讲解
上面的实现代码,如果您一眼就能看懂,证明您是经常封组件的大虾了,下面的就不用看了。如果看不懂,也没关系,我们将代码拆开详细看看里面是什么鬼。
(1)首先看看我们最常看到的如下写法:
(function ($) {
//....封装组件逻辑
})(jQuery);
初初看到这种用法,博主也是狂抓,这是什么鬼嘛,四不像啊。使用多了之后才知道原来这就是一个匿名函数的形式。将它拆开来看如下:
var fn = function($){
//.....组件封装逻辑
};
fn(jQuery);
也就是说这种写法就表示先定义一个方法,然后立即调用这个方法,jQuery相当于实参。打开jquery.js的原文件可以看到,jQuery是这个文件里面的一个全局变量。
(2)定义自己的组件的代码:
$.fn.combobox = function (options, param) {
};
习惯这种写法的应该知道,这个就表示向jquery对象添加自定义方法,比如你想使用文章开始的 $("#id").MyJsControl({}) 这种用法,你就可以这样定义 $.fn.MyJsControl=function(options){} 。
(3) options = $.extend({}, $.fn.combobox.defaults, options || {}); 这一句,看过上文的朋友应该还记得extend这么一个方法吧,怎么样,又来了你。这句话其实就没什么好说的了,合并默认参数和用户传进来的参数。
(4)默认参数列表
$.fn.combobox.defaults = {
url: null,
param: null,
data: null,
valueField: 'value',
textField: 'text',
placeholder: '请选择',
onBeforeLoad: function (param) { },
onLoadSuccess: function () { },
onChange: function (value) { }
};
如果用户没有传参,就用默认的参数列表。如果你够细心,你会发现博主之前分享的其他bootstrap组件的js文件里面都有这么一个default参数列表。我们随便找两个:
bootstrap上传组件

bootstrap table组件


基本都是这么些用法。这样来看,是否也可以自己封一个js组件~~
三、总结
以上就是博主对js组件扩展以及封装用法的认识和总结。当然,都是些比较简单基础的封装,如果想要实现类似bootstrap table的组件,那还差得很远。不过万丈高楼平地起,只要打好基础,封一个自己的table组件也不是什么大问题。文中如果有理解不对的地方,欢迎指出,博主将不胜感激。如果本文能够对你有丝毫帮助,麻烦抬起你的小手点个推荐,博主一定继续努力,将更好的文章分享给大家。
JS组件系列——封装自己的JS组件,你也可以的更多相关文章
- JS组件系列——封装自己的JS组件
前言:之前分享了那么多bootstrap组件的使用经验,这篇博主打算研究下JS组件的扩展和封装,我们来感受下JQuery为我们提供$.Extend的神奇,看看我们怎么自定义自己的组件,比如我们想扩展一 ...
- JS组件系列——又一款MVVM组件:Vue(二:构建自己的Vue组件)
前言:转眼距离上篇 JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查) 已有好几个月了,今天打算将它捡起来,发现好久不用,Vue相关技术点都生疏不少.经过这几个月的时间,Vue ...
- 原生JS面向对象思想封装轮播图组件
原生JS面向对象思想封装轮播图组件 在前端页面开发过程中,页面中的轮播图特效很常见,因此我就想封装一个自己的原生JS的轮播图组件.有了这个需求就开始着手准备了,代码当然是以简洁为目标,轮播图的各个功能 ...
- JS组件系列——两种bootstrap multiselect组件大比拼
前言:今天继续来看看bootstrap的另一个组件:multiselect.记得在项目开始之前,博主项目组几个同事就使用哪些js组件展开过讨论,其中就说到了select组件,由于项目的整体风格使用的b ...
- C#组件系列———又一款日志组件:Elmah的学习和分享
前言:好久没动笔了,都有点生疏,12月都要接近尾声,可是这月连一篇的产出都没有,不能坏了“规矩”,今天还是来写一篇.最近个把月确实很忙,不过每天早上还是会抽空来园子里逛逛.一如既往,园子里每年这个时候 ...
- C#组件系列——又一款日志组件:Elmah的学习和分享
前言:好久没动笔了,都有点生疏,12月都要接近尾声,可是这月连一篇的产出都没有,不能坏了“规矩”,今天还是来写一篇.最近个把月确实很忙,不过每天早上还是会抽空来园子里逛逛.一如既往,园子里每年这个时候 ...
- JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查)
前言:关于Vue框架,好几个月之前就听说过,了解一项新技术之后,总是处于观望状态,一直在犹豫要不要系统学习下.正好最近有点空,就去官网了解了下,看上去还不错的一个组件,就抽空研究了下.最近园子里vue ...
- JS组件系列——Bootstrap文件上传组件:bootstrap fileinput
前言:之前的三篇介绍了下bootstrap table的一些常见用法,发现博主对这种扁平化的风格有点着迷了.前两天做一个excel导入的功能,前端使用原始的input type='file'这种标签, ...
- JS组件系列——分享自己封装的Bootstrap树形组件:jqTree
前言:之前的一篇介绍了下如何封装自己的组件,这篇再次来体验下自己封装组件的乐趣.看过博主博客的园友应该记得之前分享过一篇树形菜单的使用JS组件系列——Bootstrap 树控件使用经验分享,这篇里面第 ...
随机推荐
- ASP.NET MVC之路由深究
MVC的强大之处之一当然是路由,这是几年前一位牛人给我说过的话,本人深感认同.今天就再次探究. 首先新建一个空的MVC项目,我们会发现在RouteConfig类中存在一个默认的路由配置,通常我会在这里 ...
- 有一个小效果而引出的appendTo()函数。
在公司做项目的时候,始终不了解信息逐条向上滚的动画效果,后来查阅相关资料,终于明白了,在这个过程中,让我对appendTo这个函数有了一个全新的认识.话不多说,首先是demo: <!DOCTYP ...
- Event 8306 5021 5059 5057发布安全令牌时异常
现象:站点访问一个,应用程序池就自动停掉一个 日志报错 解决: 1.受域策略影响,作为批处理作业登录选项被锁定,需修改域策略: 更新后: 2.确保程序池账户倒在IIS_IUSER组 ...
- iOS中,在类的源文件(.m)中,@interface部分的作用?
此@interface部分为类扩展(extension). 其被设计出来就是为了解决两个问题的 其一,定义类私有方法的地方. 其二,实现public readonly,private readwr ...
- 理解 iOS 的内存管理
远古时代的故事 那些经历过手工管理内存(MRC)时代的人们,一定对 iOS 开发中的内存管理记忆犹新.那个时候大约是 2010 年,国内 iOS 开发刚刚兴起,tinyfool 大叔的大名已经如雷贯耳 ...
- Git:Git初体验——Git安装配置
作为即将成为一个程序员的男人,一直在听别人说Git多好多好,之前也随便了解了一些,但是始终没有决心去学会.现在大四了,只有毕设和一门开学六七周只去过一次课的全员必修课外,也没有什么事情做,何不去做这些 ...
- [Erlang 0104] 当Erlang遇到Solr
Joe Armstrong的访谈中有一段关于"打开黑盒子"的阐述,给我留下很深的印象:Joe Armstrong在做XWindows开发时没有使用对应的类库,而是在了解XW ...
- 在Mac电脑上为iPhone或iPad录屏的方法
在以前的Mac和iOS版本下,录制iPhone或者iPad屏幕操作是一件稍微复杂的事情.但是随着Yosemite的出现,在Mac电脑上为iPhone或iPad录屏的方法就变得简单了.下面就介绍一下具体 ...
- ORACLE数据库SQL语句的执行过程
SQL语句在数据库中处理过程是怎样的呢?执行顺序呢?在回答这个问题前,我们先来回顾一下:在ORACLE数据库系统架构下,SQL语句由用户进程产生,然后传到相对应的服务端进程,之后由服务器进程执行该SQ ...
- RHEL 6.6安装桌面环境GNOME
在测试服务器(Red Hat Enterprise Linux Server release 6.6)需要安装桌面系统环境,于是选择GNOME桌面环境安装. 一:检查系统的运行级别以及是否安装了桌面环 ...