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组件也不是什么大问题。如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • JS组件系列之MVVM组件构建自己的Vue组件

    正文 前言:转眼距离上篇 JS组件系列--又一款MVVM组件:Vue(一:30分钟搞定前端增删改查) 已有好几个月了,今天打算将它捡起来,发现好久不用,Vue相关技术点都生疏不少.经过这几个月的时间,Vue的发展也是异常迅猛,不过这好像和博主都没什么太大的关系,博主还是老老实实研究自己的技术吧.技术之路还很长,且行且研究吧. 一.为什么组件很重要 前两天,看到一篇关于 汇总vue开源项目 的文章,资源非常丰富,不得不感叹开源社区的强大.随便点进去看了几个UI组件,基本都不是原生的html用法,如

  • JS组件系列之MVVM组件 vue 30分钟搞定前端增删改查

    正文 前言:关于Vue框架,好几个月之前就听说过,了解一项新技术之后,总是处于观望状态,一直在犹豫要不要系统学习下.正好最近有点空,就去官网了解了下,看上去还不错的一个组件,就抽空研究了下.最近园子里vue也确实挺火,各种入门博文眼花缭乱,博主也不敢说写得多好,就当是个学习笔记,有兴趣的可以看看. 一.MVVM大比拼 关于MVVM,原来在介绍knockout.js的时候有过讲解,目前市面上比较火的MVVM框架也是一抓一大把,比如常见的有Knockout.js.Vue.js.AvalonJS.An

  • JS组件系列之Bootstrap table表格组件神器【终结篇】

    bootstrap table系列: JS表格组件神器bootstrap table详解(基础版) JS组件系列之Bootstrap table表格组件神器[终结篇] JS组件系列之Bootstrap table表格组件神器[二.父子表和行列调序] Bootstrap Table是轻量级的和功能丰富的以表格的形式显示的数据,支持单选,复选框,排序,分页,显示/隐藏列,固定标题滚动表,响应式设计,Ajax加载JSON数据,点击排序的列,卡片视图等.那么本文给大家介绍JS组件系列之Bootstrap

  • JS组件系列之Bootstrap Icon图标选择组件

    前言:最近好多朋友在群里面聊到bootstrap icon图标的问题,比如最常见的菜单管理,每个菜单肯定需要一个对应的菜单图标,要是有一个可视化的图标选择组件就好了,最好是直接选择图标,就能得到对应的class样式.于是乎各种百度,皇天不负有心人,最后被博主找到了,感觉效果还不错,并且支持自定义的图标,今天就拿出来分享下,绝对的干货哦! 一.Bootstrap icon picker组件 这个组件是在github上面搜索的时候找到的,初初看上去,确实是很不错的,并且是基于bootstrap风格的

  • JS组件系列之使用HTML标签的data属性初始化JS组件

    前言:最近使用bootstrap组件的时候发现一个易用性问题,很多简单的组件初始化都需要在JS里面写很多的初始化代码,比如一个简单的select标签,因为仅仅只是需要从后台获取数据填充到option里面,可是从后台取数据就需要js的初始化,所以导致页面初始化的时候js的初始化代码里面出现很多重复的代码,看着很闹心.于是想起bootstrap table里面的data属性来,如果能够直接在html里面使用data-*这种方式来初始化简单的组件,那该多爽.我们先来看看bootstrap table的

  • JS组件系列之Bootstrap table表格组件神器【二、父子表和行列调序】

    Bootstrap Table是轻量级的和功能丰富的以表格的形式显示的数据,支持单选,复选框,排序,分页,显示/隐藏列,固定标题滚动表,响应式设计,Ajax加载JSON数据,点击排序的列,卡片视图等.今天就结合Bootstrap table的父子表和行列调序的用法再来介绍下它稍微高级点的用法. bootstrap table系列: JS表格组件神器bootstrap table详解(基础版) JS组件系列之Bootstrap table表格组件神器[终结篇] JS组件系列之Bootstrap t

  • vue+element树组件 实现树懒加载的过程详解

    一.页面样式 二.数据库 三.前端页面代码 <template> <el-tree :props="props" :load="loadNode" lazy show-checkbox> </el-tree> </template> <script> export default { data () { return { props: { label: 'name', children: 'zones',

  • C++音乐播放按钮的封装过程详解

    1.准备工作:音乐.开发工具VS stdio及图形库工具 2.设计思路:先加载音乐,再通过点击不同的按钮执行不同的操作(播放音乐,暂停音乐.继续播放.结束播放) 绘制按钮我们通过一个按钮button类来操作,这样数据会存在一些必要的访问数据权限,并可以将多个函数声明写在同一个类中,调用只需使用 " 类名.函数名 “即可调用里面的函数 按钮类头文件:-----button.h #include "graphics.h" #include <iostream> #in

  • JS组件系列之JS组件封装过程详解

    前言: 之前分享了那么多bootstrap组件的使用经验,这篇文章打算研究下JS组件的扩展和封装,我们来感受下JQuery为我们提供$.Extend的神奇,看看我们怎么自定义自己的组件,比如我们想扩展一个$("#id").MyJsControl({})做我们自己的组件,我们该如何去做呢,别急,我们慢慢来看看过程. 一.扩展已经存在的组件 1.需求背景 很多时候,我们使用jquery.ajax的方式向后台发送请求,型如 $.ajax({ type: "post", u

  • JS加载解析Markdown文档过程详解

    网上有很多网站会通过.md文档来做页面内容,很好奇,这是怎么做的? 出于好奇,建了一个test.md文件: # Hello World! asdfa asd *斜体文本* **粗体文本** ***斜粗体文本*** 分隔线(如下) *** * * * **** - - - ----------- GOOGLE.COM ~~删除线~~ <u>下划线</u> 用浏览器打开之后,结果就被原封不动的输出来了,浏览器根本不会解析这玩意... 跟阮老师的blog相差好大啊~呵呵~还是太天真了!

  • JS实现图片懒加载(lazyload)过程详解

    对于图片较多的页面,使用懒加载可以大幅提高页面加载速度,提高用户体验. 懒加载的意义(为什么要使用懒加载) 对页面加载速度影响最大的就是图片,一张普通的图片可以达到几M的大小,而代码也许就只有几十KB.当页面图片很多时,页面的加载速度缓慢,几S钟内页面没有加载完成,也许会失去很多的用户. 所以,对于图片过多的页面,为了加速页面加载速度,所以很多时候我们需要将页面内未出现在可视区域内的图片先不做加载, 等到滚动到可视区域后再去加载.这样子对于页面加载性能上会有很大的提升,也提高了用户体验. 原理

  • React18系列reconciler从0实现过程详解

    目录 引言 React-Dom包 createRoot hostConfig.ts React-reconciler包 createContainer() 函数 render() 调用 创建更新createUpdate 将更新推进队列enqueueUpdate 开始调用scheduleUpdateOnFiber wookLoop beginWork开始 updateHostRoot reconcileChildren reconcileSingleElement 例子 completeWork开

  • springmvc数据的封装过程详解

    spring封装是进行orm封装,可以进行定义数据类型,数据名与接收名相同,进行接收,或者定义类,类的属性名与接收名相同 单个数据类型如图下: 对象类型封装: 其他:乱码处理 在中文字符乱码,需要规定请求响应的编码,可以自己进行过滤器进行过滤设置,但是jar包中给我们提供了此过滤器,我们只需要进行web.xml配置即可 init-param规定的是编译的类型 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们.

  • Python自动化测试PO模型封装过程详解

    在自动化中, Selenium 自动化测试中有一个名字经常被提及 PageObject( 思想与面向对象的特征相 同 ) ,通常 PO 模型可以大大提高测试用例的维护效率 优点:可重用,业务和对象分离,代码结构清晰,方便代码维护 核心要素 1. 在 PO 模式中抽离封装集成一个BasePage 类,该基类应该拥有一个只实现 webdriver 实例的属性 2. 每一个 page 都继承 BasePage ,通过 driver 来管理本 page 中元素,将 page 中的操作封装成一个个方法 3

  • 封装一个更易用的Dialog组件过程详解

    目录 场景 搭建环境 创建组件 创建调用组件的hook函数 Dialog的缓存.隐藏 隐藏 缓存 完整代码 总结 场景 在项目中,我们经常会遇到使用弹窗的场景,但有时组件库自带的弹窗不能满足我们的需求,需要我们自己封装,这时我们如何去自定义一个更加方便调用的弹窗? 搭建环境 首先我们需要搭建一个Vue3+ts的环境. 用vite的官方模板: yarn create vite demo-app --template vue-ts 进入并安装依赖 cd demo-app yarn 依赖安装完成后启动

随机推荐