`
zachary.guo
  • 浏览: 487832 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

A Plugin Development Pattern For jQuery

阅读更多
This article comes from http://www.learningjquery.com/2007/10/a-plugin-development-pattern

I've been developing jQuery plugins for quite a while now, and I've become rather comfortable with a particular style of plugin development for my scripts. This article is meant to share the pattern that I've found especially useful for plugin authoring. It assumes you already have an understanding of plugin development for jQuery; if you're a novice plugin author, please review the jQuery Authoring Guidelines first.

There are a few requirements that I feel this pattern handles nicely:
  1. Claim only a single name in the jQuery namespace
  2. Accept an options argument to control plugin behavior
  3. Provide public access to default plugin settings
  4. Provide public access to secondary functions (as applicable)
  5. Keep private functions private
  6. Support the Metadata Plugin

I'll cover these requirements one by one, and as we work through them we'll build a simple plugin which highlights text.

Claim only a single name in the jQuery namespace
This implies a single-plugin script. If your script contains multiple plugins, or complementary plugins (like $.fn.doSomething() and $.fn.undoSomething()) then you'll claim multiple names are required. But in general when authoring a plugin, strive to use only a single name to hold all of its implementation details.

In our example plugin we will claim the name "hilight".
// plugin definition
$.fn.hilight = function() {
  // Our plugin implementation code goes here.
};

And our plugin can be invoked like this:
$('#myDiv').hilight();


But what if we need to break up our implementation into more than one function? There are many reasons to do so: the design may require it; it may result in a simpler or more readable implementation; and it may yield better OO semantics.

It's really quite trivial to break up the implementation into multiple functions without adding noise to the namespace. We do this by recognizing, and taking advantage of, the fact that functions are first-class objects in JavaScript. Like any other object, functions can be assigned properties. Since we have already claimed the "hilight" name in the jQuery prototype object, any other properties or functions that we need to expose can be declared as properties on our "hilight" function. More on this later.

Accept an options argument to control plugin behavior
Let's add support to our hilight plugin for specifying the foreground and background colors to use. We should allow options like these to be passed as an options object to the plugin function. For example:
// 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.
};

Now our plugin can be invoked like this:
$('#myDiv').hilight({
  foreground: 'blue'
});


Provide public access to default plugin settings
An improvement we can, and should, make to the code above is to expose the default plugin settings. This is important because it makes it very easy for plugin users to override/customize the plugin with minimal code. And this is where we begin to take advantage of the function object.
// 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'
};

Now users can include a line like this in their scripts:
// this need only be called once and does not
// have to be called from within a 'ready' block
$.fn.hilight.defaults.foreground = 'blue';

And now we can call the plugin method like this and it will use a blue foreground color:
$('#myDiv').hilight();

As you can see, we've allowed the user to write a single line of code to alter the default foreground color of the plugin. And users can still selectively override this new default value when they want:
// 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'
});


Provide public access to secondary functions as applicable
This item goes hand-in-hand with the previous item and is an interesting way to extend your plugin (and to let others extend your plugin). For example, the implementation of our plugin may define a function called "format" which formats the hilight text. Our plugin may now look like this, with the default implementation of the format method defined below the hilight function.
// 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>';
};

We could have just as easily supported another property on the options object that allowed a callback function to be provided to override the default formatting. That's another excellent way to support customization of your plugin. The technique shown here takes this a step further by actually exposing the format function so that it can be redefined. With this technique it would be possible for others to ship their own custom overrides of your plugin נin other words, it means others can write plugins for your plugin.

Considering the trivial example plugin we're building in this article, you may be wondering when this would ever be useful. One real-world example is the Cycle Plugin. The Cycle Plugin is a slideshow plugin which supports a number of built-in transition effects נscroll, slide, fade, etc. But realistically, there is no way to define every single type of effect that one might wish to apply to a slide transition. And that's where this type of extensibility is useful. The Cycle Plugin exposes a "transitions" object to which users can add their own custom transition definitions. It's defined in the plugin like this:
$.fn.cycle.transitions = {
 // ...
};

This technique makes it possible for others to define and ship transition definitions that plug-in to the Cycle Plugin.

Keep private functions private
The technique of exposing part of your plugin to be overridden can be very powerful. But you need to think carefully about what parts of your implementation to expose. Once it's exposed, you need to keep in mind that any changes to the calling arguments or semantics may break backward compatibility. As a general rule, if you're not sure whether to expose a particular function, then you probably shouldn't.

So how then do we define more functions without cluttering the namespace and without exposing the implementation? This is a job for closures. To demonstrate, we'll add another function to our plugin called "debug". The debug function will log the number of selected elements to the Firebug console. To create a closure, we wrap the entire plugin definition in a function (as detailed in the 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);

Our "debug" method cannot be accessed from outside of the closure and thus is private to our implementation.

Support the Metadata Plugin
Depending on the type of plugin you're writing, adding support for the Metadata Plugin can make it even more powerful. Personally, I love the Metadata Plugin because it lets you use unobtrusive markup to override plugin options (which is particularly useful when creating demos and examples). And supporting it is very simple!
Update: This bit was optimized per suggestion in the comments.
// 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;
  //...

This changed line does a couple of things:
  • it tests to see if the Metadata Plugin is installed
  • if it is installed, it extends our options object with the extracted metadata

This line is added as the last argument to jQuery.extend so it will override any other option settings. Now we can drive behavior from the markup if we choose:
<!--  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>

And now we can hilight each of these divs uniquely using a single line of script:
$('.hilight').hilight();


Putting it All Together
Below is the completed code for our example:
// 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);

This design pattern has enabled me to create powerful, consistently crafted plugins. I hope it helps you to do the same.
分享到:
评论

相关推荐

    jquery 英文教程 jQuery Plugin Development Beginner’s Guide PDF

    jquery 的经典 英文书 jQuery Plugin Development Beginner’s Guide.PDF

    jQuery plugin for autocomplete - jQuery自动完成插件

    jQuery plugin for autocomplete - jQuery自动完成插件

    The Basic of Plugin Development for IntelliJ IDEA

    The Basics of Plugin Development for IntelliJ IDEA. Alexey Efimov 1 This article helps you to quickly understand the basics of plugin development for IntelliJIDEA in order to start writing your own ...

    Lazy Load Plugin for jQuery demo

    标题 "Lazy Load Plugin for jQuery demo" 暗示这是一个关于如何使用 jQuery Lazy Load 插件的实际演示。在这个项目中,我们可以期待看到如何配置和集成该插件,以及在不同场景下它的实际运行效果。这个演示可能包含...

    jQuery全能权威指南:jQuery Core+jQuery Plugin+jQuery UI+jQuery Mobile 源码

    、CSS和JavaScript知识的开发者,内容覆盖了jQuery知识体系的全部内容,包括jQuery Core、jQuery Plugin 、jQuery UI、jQuery Mobile以及大量第三方的插件库和2800多个应用jQuery技术的网页参考。

    jQuery摄像头插件jquery-webcam-plugin

    **jQuery摄像头插件jquery-webcam-plugin** 在网页开发中,集成摄像头功能可以帮助用户实时捕捉图像,广泛应用于在线证件照上传、视频聊天、虚拟试衣间等场景。`jQuery webcam plugin`是一个优秀的JavaScript库,它...

    WordPress Plugin Development Cookbook(2nd) mobi

    WordPress Plugin Development Cookbook(2nd) 英文mobi 第2版 本资源转载自网络,如有侵权,请联系上传者或csdn删除 查看此书详细信息请在美国亚马逊官网搜索此书

    WordPress Plugin Development Cookbook(2nd) epub

    WordPress Plugin Development Cookbook(2nd) 英文epub 第2版 本资源转载自网络,如有侵权,请联系上传者或csdn删除 查看此书详细信息请在美国亚马逊官网搜索此书

    jQuery输入格式的插件Masked Input Plugin

    《jQuery输入格式插件Masked Input Plugin深度解析》 在Web开发中,用户界面的交互性和数据输入的规范性是提升用户体验的关键因素。jQuery Masked Input Plugin是一款强大的JavaScript库,它能够帮助开发者轻松地...

    jQuery Media Plugin Demo

    jQuery Media Plugin是一款专门为jQuery设计的多媒体插件,用于在网页中轻松集成音频、视频和图像等多媒体元素。这款插件的出现,极大地简化了开发者在HTML5时代处理多媒体内容的复杂性,使得开发者无需深入了解...

    Cookie Plugin for jQuery

    《jQuery Cookie插件详解与应用实践》 在Web开发中,Cookie作为一种小型文本文件,用于在客户端存储数据,常用于用户会话管理、个性化设置等场景。jQuery Cookie插件是jQuery库的一个扩展,它简化了JavaScript操作...

    JQuery Cycle Plugin

    **jQuery Cycle Plugin** 是一个广泛使用的JavaScript库,专门用于创建动态和交互式的图像滑块、轮播和幻灯片效果。这个插件充分利用了jQuery的简洁API和强大的DOM操作功能,使得开发者能够轻松地在网站上实现各种...

    jQuery Validation Plugin1.19.5(jQuery验证插件最新)

    jQuery 插件使客户端表单验证变得容易,同时仍然提供了大量的自定义选项。如果您要从头开始构建新的东西,或者当您试图将某些东西集成到具有大量现有标记的现有应用程序中时,它都是一个不错的选择。该插件捆绑了一...

    EasyUI for JQuery官方文档.pdf

    EasyUI组件的方法和事件的实现,通常是通过在jQuery.fn.{plugin}.methods和jQuery.fn.{plugin}.defaults中定义的。每个方法通常有两个参数:jq和param。其中jq是必需的,指的是jQuery对象;param则是传递给方法的...

    jQuery Orbit Plugin 1.2.3

    jQuery Orbit Plugin 1.2.3 是一个专为网页设计者和开发者打造的高效、灵活的轮播插件。这个版本的Orbit Plugin是jQuery库的一个扩展,它提供了丰富的功能和自定义选项,使得创建吸引人的图片轮播、内容滑动效果变得...

    JQuery validation plugin学习资料

    **jQuery Validation Plugin 知识详解** jQuery Validation Plugin 是一个用于前端表单验证的强大工具,它为jQuery用户提供了方便快捷的方法来验证用户输入的数据,确保数据的准确性和完整性。这个插件能够帮助...

    jquery-plugin

    jquery-plugin:开发Jquery插件的简单示例,

    Ellipsis – Jquery Ellipsis Plugin

    **jQuery Ellipsis 插件详解** 在Web开发中,我们经常遇到一个问题:如何优雅地处理过长的文字内容,尤其是在有限的显示空间内。这正是jQuery Ellipsis插件所解决的问题。该插件提供了一个简洁而实用的方法,可以...

    struts2-jquery-plugin插件3.3.3

    最新的struts2-jquery-plugin插件3.3.3,包括jquery-ui和grid,使用标签实现。

Global site tag (gtag.js) - Google Analytics