一、扩展已经存在的组件
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组件扩展以及封装用法的认识和总结,希望大家喜欢。
本文向大家介绍使用java数组 封装自己的数组操作示例,包括了使用java数组 封装自己的数组操作示例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了使用java数组 封装自己的数组操作。分享给大家供大家参考,具体如下: 今天感冒了,全身酸软无力,啥样不想做,就来学习吧,此节我们从初步使用java中提供的数组,然后分析相关情况,过渡到封装我们自己的数组。 一.我们先来感受一下java提供的
本文向大家介绍vue element-ui之怎么封装一个自己的组件的详解,包括了vue element-ui之怎么封装一个自己的组件的详解的使用技巧和注意事项,需要的朋友参考一下 为什么要进行组件封装? 封装的目的就是为了能够更加便捷、快速的进行业务功能的开发。组件(component)是vue的最强大功能之一,组件可以实现一些类似功能的复用及与其它业务逻辑的解耦。在开发中,我们难免会写很多类似的
本文向大家介绍自己封装的javascript事件队列函数版,包括了自己封装的javascript事件队列函数版的使用技巧和注意事项,需要的朋友参考一下 背景 javascript中使用addEventListener()或attachEvent()绑定事件时会有几个小问题: 一、使用addEventListener()或attachEvent()添加的匿名函数无法移除。 二、ie6-ie8中,使用
本文向大家介绍自己封装的常用javascript函数分享,包括了自己封装的常用javascript函数分享的使用技巧和注意事项,需要的朋友参考一下 都是些常用的功能,这里就不多废话了,小伙伴们自己看下就明白了 奉上代码:
本文向大家介绍简单了解如何封装自己的Python包,包括了简单了解如何封装自己的Python包的使用技巧和注意事项,需要的朋友参考一下 将自己的程序打包为whl/tar.gz文件 有时候自己写了一个开发基本类,我们把这个类打包为whl或者tar.gz文件,这样的话同事也可以使用自己开发的基本类了 安装setuptools pip install setuptools 编写setup.py及__in
本文向大家介绍IOS定制属于自己的个性头像,包括了IOS定制属于自己的个性头像的使用技巧和注意事项,需要的朋友参考一下 本文实例介绍了IOS定制属于自己的个性头像的方法,分享给大家供大家参考,具体内容如下 一、效果图 1、将一张图片剪切成圆形 2、在图片周围显示指定宽度和颜色的边框 二、实现思路 1、效果图中主要由不同尺寸的两大部分组成 蓝色的背景区域,尺寸等于图片的尺寸加上边框的尺寸 图片区域,