文档章节

(jQuery)插件开发模式

laichendong
 laichendong
发布于 2014/06/25 09:27
字数 2360
阅读 1412
收藏 144
点赞 6
评论 6

前几天一个工作需要,写了一个jquery的小插件,想起来这篇让我受益匪浅的老文章,翻译出来给大家看看。这是我翻译的第一篇文章,如果觉得实在太差,看不下去了,请移步原文: http://www.learningjquery.com/2007/10/a-plugin-development-pattern 。真的是好文一篇! ----------------------------------我只是分割线------------------------------------------ 我开发jQuery插件已经有一段时间了,这个过程中我形成了一个很舒服的插件开发风格。这篇文章我就介绍一下我发现的这个对插件开发很有帮助的模式。这里我假设你对jQuery插件的开发已经有一个基本的理解了。如果你还是个新手,建议你先看一下 jQuery Authoring Guidelines 这里列举一些我认为这个模式做得好的点(requirements)

  1. 在jQuery的命名空间中声明一个简单(唯一)的名字

  2. 接收一些可选的参数来控制插件的行为

  3. 提供对插件默认配置的访问方法

  4. 提供对辅助功能的访问方法

  5. 保持私有方法是私有的

  6. 支持插件元数据(the Metadata Plugin)

下面我将对上面这些点逐一解释,并且按照他们实现一个文本高亮的小插件。

在jQuery的命名空间中声明一个简单(唯一)的名字

这句话的隐含意思是:单一插件的脚本(a  single-plugin script),假如你的脚本中包含多个插件,或者一对功能对称的插件(比如$.fn.doSomething() 和 $.fn.undoSomething() ),那么你应该声明多个名字。一般情况下。我们开发插件的时候,都力求做到能用一个简单的名字来包含/表达插件所有的功能细节。 在我们接下来的这个例子中,我们就用“hilight”这个名字。

// plugin definition
$.fn.hilight = function() {
  // Our plugin implementation code goes here.
};

然后,可以这样调用我们的插件:

$('#myDiv').hilight();

如果要将我们的实现拆成多个函数该怎么办呢?我们有足够的理由要拆成多个函数,比如:设计的需要啊;代码可读性的需要啊;为了符合OO语义的需要啊;等等。 将实现拆分成多个函数且不污染jQuery的命名空间其实挺微琐碎的一件事儿。我们借着“在JavaScript中,function就是一级对象”的特性有意识的来做到这点。和其他对象一样,function也可以有自己的属性。我们刚刚已经在jQuery的原型对象上声明了一个“hilight”。然后任何需要被暴露的属性和方法我们都可以作为hilight函数的属性声明出来。这个等会儿还会作详细解释。

接收一些可选的参数来控制插件的行为

我们给hilight插件加上指定特定前景色和背景色的功能。我们需要允许向插件函数传递一个配置对象来进行配置。比如这样:

// plugin definition
$.fn.hilight = function(options) {
  var defaults = {
    foreground: 'red',
    background: 'yellow'
  };
  // Extend our default options with those provided.
  var opts = $.extend(defaults, options);
  // Our plugin implementation code goes here.
};

现在我们的插件就可以这样调用了。

$('#myDiv').hilight({
  foreground: 'blue'
});

提供对插件默认配置的访问方法

我们可以(应该)将插件的默认配置用下面的方法暴露出去。这很重要,因为这可以让插件的使用者用很容易用很少的代码来覆盖/自定义插件。然后这里我们就利用到了function对象作为“一级对象”的便利特性。

// plugin definition
$.fn.hilight = function(options) {
  // Extend our default options with those provided.
  // Note that the first arg to extend is an empty object -
  // this is to keep from overriding our "defaults" object.
  var opts = $.extend({}, $.fn.hilight.defaults, options);
  // Our plugin implementation code goes here.
};
// plugin defaults - added as a property on our plugin function
$.fn.hilight.defaults = {
  foreground: 'red',
  background: 'yellow'
};

现在,用户就可以在他们的代码中写这么一行:

// this need only be called once and does not
// have to be called from within a 'ready' block
$.fn.hilight.defaults.foreground = 'blue';

然后依然用这种方法调用我们的插件,就可以用蓝色做为前景色了

$('#myDiv').hilight();

正如你所见,用户可以像这样写一行简单的代码就能改变插件默认的前景色。而且用户仍然可以选择覆盖这个新的默认值:

// override plugin default foreground color
$.fn.hilight.defaults.foreground = 'blue';
// ...
// invoke plugin using new defaults
$('.hilightDiv').hilight();
// ...
// override default by passing options to plugin method
$('#green').hilight({
  foreground: 'green'
});

提供对辅助功能的访问方法

这一条和前面几条是紧密相连的,是一个扩展你的插件的有趣的方式(包括让别人来扩展你的插件)。例如,我们的实现中可能包含一个叫format的方法来对要高亮的文本进行格式化。这时我们的插件看起来是这样的,我们在hilight方法下面提供了一个format方法的默认实现。

// plugin definition
$.fn.hilight = function(options) {
  // iterate and reformat each matched element
  return this.each(function() {
    var $this = $(this);
    // ...
    var markup = $this.html();
    // call our format function
    markup = $.fn.hilight.format(markup);
    $this.html(markup);
  });
};
// define our format function
$.fn.hilight.format = function(txt) {'
 return '<strong>' + txt + '</strong>';
};

我们也可以简单的在配置对象中提供一个属性来作为回调函数来达到覆盖默认的格式化。这是另一种让你的插件支持可定制化的好方法。这里展示的是进一步的将format方法暴露出去,让别人可以对他进行重新定义。通过这种技术,别人可以将他们自己对你的插件的修改提供给其他人用,换句话说,就是能让别人给你的插件写插件。 在我们这篇文章中介绍的这个小插件中,你可能认为这没什么用。有一个真实的例子是  Cycle Plugin,Cycle Plugin是一个提供了很多内置动画效果(滚动,滑动,淡入淡出)的幻灯片插件。但是事实上,他没有提供一种实现简单的幻灯片切换效果的途径。那,这里就是上面这种扩展方式非常有用的地方了。Cycle Plugin就暴露了一个叫“transitions”的对象,让用户可以自己定义幻灯片的切换效果。在他插件代码里就是这样写的:

$.fn.cycle.transitions = {
 // ...
};

这种技术就让其他人为Cycle Plugin编写幻灯片切换效果成为可能了。

保持私有函数私有

将你的插件部分功能暴露出去让他们可以被覆盖是一个很强大的技术。但是你需要想清楚,你的哪部分实现是需要暴露出去的。一旦你暴露出去了,就要时刻提醒自己:对这个函数的调用参数和语义做任何修改都可能破坏他的向后兼容性。一般的规则是,如果你不确定这个函数该不该被暴露出去,那就不要暴露出去。 那么我如何在既不污染命名空间又不将函数暴露出去的情况下添加更多的函数呢?这就是闭包(closures)干的事儿。为了演示,我们在插件里再添加一个叫“debug”的函数。debug函数将在FireBug的控制台上记录被选择的元素的数量。为了建立一个闭包,我们将整个插件的定义包起来(详见  jQuery Authoring Guidelines)。

// create closure
(function($) {
  // plugin definition
  $.fn.hilight = function(options) {
    debug(this);
    // ...
  };
  // private function for debugging
  function debug($obj) {
    if (window.console && window.console.log)
      window.console.log('hilight selection count: ' + $obj.size());
  };
 //  ...
// end of closure
})(jQuery);

这样debug方法不能被闭包外面的代码所访问到,所以,它就是我们插件私有的了。

支持插件元数据

根据你写的插件的类型,提供对元数据的支持,可以让它变得更加强大。我个人喜欢它的原因是因为它可以让你用不那么扎眼的html标签就能修改插件的默认配置(这点在写示例的时候非常有用)。而且实现起来也很简单!

// plugin definition
$.fn.hilight = function(options) {
  // ...
  // build main options before element iteration
  var opts = $.extend({}, $.fn.hilight.defaults, options);
  return this.each(function() {
    var $this = $(this);
    // build element specific options
    var o = $.meta ? $.extend({}, opts, $this.data()) : opts;
    //...

改变的这行做了下面这些事儿:

  • 检查是否安装了元数据

  • 如果安装了,用安装的元数据扩展我们的配置对象

让元数据作为jQuery.extend方法的最后一个参数,保证前面的配置一定会被它覆盖。现在,我们可以选择用标签来驱动插件的行为了。

<!--  markup  -->
<div class="hilight { background: 'red', foreground: 'white' }">
  Have a nice day!
</div>
<div class="hilight { foreground: 'orange' }">
  Have a nice day!
</div>
<div class="hilight { background: 'green' }">
  Have a nice day!
</div>

然后现在我们可以用一行代码就可以让每个div拥有不同的行为了。

$('.hilight').hilight();

 来个总结

下面是我们这个例子的完整代码:

//
// create closure
//
(function($) {
  //
  // plugin definition
  //
  $.fn.hilight = function(options) {
    debug(this);
    // build main options before element iteration
    var opts = $.extend({}, $.fn.hilight.defaults, options);
    // iterate and reformat each matched element
    return this.each(function() {
      $this = $(this);
      // build element specific options
      var o = $.meta ? $.extend({}, opts, $this.data()) : opts;
      // update element styles
      $this.css({
        backgroundColor: o.background,
        color: o.foreground
      });
      var markup = $this.html();
      // call our format function
      markup = $.fn.hilight.format(markup);
      $this.html(markup);
    });
  };
  //
  // private function for debugging
  //
  function debug($obj) {
    if (window.console && window.console.log)
      window.console.log('hilight selection count: ' + $obj.size());
  };
  //
  // define and expose our format function
  //
  $.fn.hilight.format = function(txt) {
    return '<strong>' + txt + '</strong>';
  };
  //
  // plugin defaults
  //
  $.fn.hilight.defaults = {
    foreground: 'red',
    background: 'yellow'
  };
//
// end of closure
//
})(jQuery);

这个设计模式,让我能够开发出更加强大,结构更加一致的插件。希望它对你也有同样的效果。  

© 著作权归作者所有

共有 人打赏支持
laichendong
粉丝 8
博文 85
码字总数 71483
作品 0
朝阳
程序员
加载中

评论(6)

itpkm
itpkm
这个很不错!
bkkkd
bkkkd
不错。
laichendong
laichendong

引用来自“zp-wmhx”的评论

不错,讲的很细致.
谢谢
laichendong
laichendong

引用来自“悲催不悲催”的评论

很好,身为后台的码农,前端也是要了解。
谢谢
悲催不悲催
悲催不悲催
很好,身为后台的码农,前端也是要了解。
酷酷的就
酷酷的就
不错,讲的很细致.
强大的JQuery-自定义插件

====jQuery插件编写原则===== 1.命名 jQuery..js 2.插件内部,this指向的是当前选择器取得的JQuery对象,不是内部对象, 例如click(), 内部的this指向的是DOM元素 3.this.each可以遍历所有元素...

chengfei_liu ⋅ 05/25 ⋅ 0

jQuery之validate验证表单

访问jQuery validate官网下载最新插件 https://jqueryvalidation.org/ validate是用来验证表单的 以前我们都是用js手动验证 现在可以通过这个插件直接调用别人写好的方法 更加简单方便 vali...

codingcoge ⋅ 05/19 ⋅ 0

来学着写自己的“jQuery”

jQuery是一套跨浏览器的JavaScript库,简化HTML与JavaScript之间的操作 jQuery是开源软件,使用MIT许可证授权。jQuery的语法设计使得许多操作变得容易,如操作文档对象(document)、选择文档...

YyzclYang ⋅ 05/24 ⋅ 0

Python自动化开发学习17-jQuery

jQuery学习之前 jQuery 是 JavaScript 的一个类库,类似 python 中的模块。 jQuery在线手册:http://jquery.cuishifeng.cn/ 官网:http://jquery.com/ 版本选择 目前jQuery有三个大版本:1.x...

骑士救兵 ⋅ 前天 ⋅ 0

【BS学习】jQuery视频总结

【背景】 这两天看完了jQuery视频的视频,对学习到的东西做一个记录。 【内容】 一、JQuery框架简介 1、官方网站:www.jquery.com 2.创立者:John Resig 3.历史: 4.特点:(1)Write Less,...

yym15732626210 ⋅ 03/12 ⋅ 0

多功能下拉分页选择插件 - SelectPage

多功能下拉选择插件 SelectPage 简洁而强大的下拉分页选择器;支持远程数据(AJAX)、 autocomplete、键盘快速导航操作、分页展示、多选标签、i18n国际化支持等多功能的选择器插件 入门指南、...

TerryZ ⋅ 2017/06/13 ⋅ 10

huangdf/seezoon-framework-all

项目介绍 基于spring,mybatis,shiro面向接口开发的的一套后台管理系统,方便快速开发;采用常用的技术栈,降低学习成本,项目完全前后端分离,后端定义统一的接口格式,统一参数校验,统一权...

huangdf ⋅ 04/20 ⋅ 0

JS生成二维码 jquery.qrcode 插件

使用jquery.qrcode生成二维码 二维码应用已经成为app 和网页的标配,那么在开发中不少人问,怎么生成二维码,现在我就讲解一种 js 直接生成图片的方法,后台都无需参与,前端就是牛 本文将介...

xllily_11 ⋅ 2017/11/14 ⋅ 0

jQuery学习笔记--选择器和事件

以下内容参考 W3school 简书 你要是问我什么是jQuery 那可以这么两句话概括: jQuery 是一个 JavaScript 库。 jQuery 极大地简化了 JavaScript 编程。 要学jQuery最好有点javaScript的基础 ...

codingcoge ⋅ 05/17 ⋅ 0

鼠标移入移出效果 -- jQuery/Vue版

元素内遮罩层根据鼠标方向显示的效果比较常见,比如百度图片里的图片信息展示。自己动手实现jQuery插件版和Vue组件版效果。 原文链接 实现思路 1、根据鼠标的位置定位在元素内出现的方向 2、...

bestvist ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Java集合类总结笔记

一、集合类的层次关系 主要容器集合类的特点: ArrayList 一种可以动态增长和缩减的索引序列 LinkedList 一种可以在任何位置进行高效地插入和删除的有序序列 ArrayDeque 一种用循环数组实现的...

edwardGe ⋅ 2分钟前 ⋅ 0

spring RMI远程调用

RMI https://www.cnblogs.com/wdh1995/p/6792407.html

BobwithB ⋅ 7分钟前 ⋅ 0

Jenkins实践2 之基本配置

1 插件管理 系统管理->插件管理 在可选插件中可以自主安装插件 2 管理用户 系统管理->管理用户->新建用户 3 安全配置 系统管理->全局安全配置 授权策略 选择安全矩阵 然后添加现有的用户,赋...

晨猫 ⋅ 7分钟前 ⋅ 0

c++智能指针

1、是一种泛型类,针对指针类型的泛型类,会保存指针 2、重载了符号 *和-> 对智能指针使用这两个符号,相当于对保存的泛型使用这两个符号 3、当智能指针引用计数为0时,会去释放指针指向的资...

国仔饼 ⋅ 9分钟前 ⋅ 0

Spring Boot错误处理机制

1)、SpringBoot默认的错误处理机制 默认效果: 1)、浏览器,返回一个默认的错误页面 浏览器发送请求的请求头: 2)、如果是其他客户端,默认响应一个json数据 原理: 可以参照ErrorMvcAut...

小致dad ⋅ 10分钟前 ⋅ 0

ftp连接不上的终极办法 SFTP

假如FTP由于各种原因就是连不上,那么用SFTP协议吧,使用登录服务器的账号密码。

sskill ⋅ 15分钟前 ⋅ 0

Unity 围绕旋转角度限制(Transform.RotateAround)

在 Unity 中可以利用 Transform.RotateAround 围绕指定物体进行旋转,但某些情况下可能需要对旋转角度进行控制。我是先计算出预设角度大小,然后判断是否在限定角度范围内是则进行旋转。 相关...

大轩 ⋅ 15分钟前 ⋅ 0

阿里沙箱环境支付宝测试demo

阿里支付宝支付和微信支付,包括:阿里沙箱环境支付宝测试demo,支付宝支付整合到spring+springmvc+mybatis环境和微信整合到如上环境,功能非常齐全,只需要修改对应的配置文件即可,帮助文档...

码代码的小司机 ⋅ 18分钟前 ⋅ 0

JDK1.6和JDK1.7中,Collections.sort的区别,

背景 最近,项目正在集成测试阶段,项目在服务器上运行了一段时间,点击表格的列进行排序的时候,有的列排序正常,有的列在排序的时候,在后台会抛出如下异常,查询到不到数据,而且在另外一...

tsmyk0715 ⋅ 35分钟前 ⋅ 0

C++ 中命名空间的 5 个常见用法

相信小伙伴们对C++已经非常熟悉,但是对命名空间经常使用到的地方还不是很明白,这篇文章就针对命名空间这一块做了一个叙述。 命名空间在1995年被引入到 c++ 标准中,通常是这样定义的: 命名...

柳猫 ⋅ 39分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部