代码改变世界

如何创建一个基础jQuery插件

2013-10-14 04:53  BrokenJar  阅读(255)  评论(0编辑  收藏  举报

如何创建一个基础插件

How to Create a Basic Plugin

  有时你想使一块功能性的代码在你代码的任何地方有效.比如,也许你想调用jQuery对象的一个方法,对该对象进行一系列的操作.可能你写了一个真正有用的实用函数,想它能够轻易的移植到其他项目.在这种情况下,你可能想写一个插件.

  Sometimes you want to make a piece of functionality available throughout your code. For example, perhaps you want a single method you can call on a jQuery selection that perfroms a series of operations on the selection. Maybe you wrote a really useful utility function that you want to be able to move easily to other projects. In this case, you may want to write a plugin.

jQuery是如何工作的 101:jQuery 对象方法和实用方法

How jQuery Works 101:jQuery Object Methods and Utility Methods

  在我们写我们自己的插件之前, 我们必须先对jQuery如何工作有一些了解.请看看这段代码:

  Before we write our own plugins, we must first understand a little about how jQuery works.Take a look at this code:

$("a").css("color", "red");

  这是一段简单的jQuery代码,但是你知道在幕后发生了什么吗?每当你使用 $ 函数来选择元素,他会返回一个jQuery对象.这个对象包含了所有你以前使用过的方法(.css(), .click() 等等)和适合你的选择器的所有元素.jQuery对象从 $.fn 对象获取这些这些方法.这个对象包含了所有jQuery对象的方法,如果我们想写我们自己的方法,它也必须包含在内.

  This is some pretty basic jQuery code, but do you know what's happning behind the scenes?Whenever you use the $ function to select elements, it returns a jQuery object. This object contains all of the methods you've been using(.css(), .click(), etc.)and all of the elements that fit your selector. The jQuery object gets these methods from the $.fn object. This object contains all of the jQuery object methods, and if we want to write our own methods, it will need to contain those as well.

  此外jQuery实用函数 $.trim() 用来删除用户输入前后的空白符.实用方法是直接属于 $ 函数本身的.当jQuery API没有对你检索到的DOM元素组实现预期功能时,你也许有时想写一个实用函数插件对其进行扩展.

  Additionally the jQuery utility method $.trim() it used above to remove any leading or trailing empty space characters from the user input. Utility methods are functions that reside directly in the $ function itself. You may occasionally want to write a utility method plugin when your extension to the jQuery API does not have to do something to a set of DOM elements you've retrieved.

基本插件创作

Basic Plugin Authoring

  比如说我们想创建一个使检索到的元素变绿的插件.我们要做的就是在 $.fn 中添加一个名为 greenify 的函数,它会像其他jQuery对象函数一样有效.

  Let's say we want to create a plugin that makes test within a set of retrieved elements green. All we have to do is add a function called greenify to $.fn and it will be available just like any other jQuery object method.

$.fn.greenify = function(){
this.css("color", "green");
}
$("a").greenify();

注意使用 .css() 和其他类似方法时,我们用 this 而不是 $(this).这是因为我们的 greenify 函数和 .css() 是同一个对象的一部分.

Notice that use .css(), another method, we use this, not $(this). This is because our greenify function is a part of the same object as .css().

连贯性

Chaining

  它工作了,但是实际上我们会有几件事情要做,jQuery的特性之一就是连贯性,当你链接了四到五个动作到一个选择器.这是通过所有的 jQuery 对象方法再次返回源 jQuery 对象来实现的(这里有一些例外: 无参数调用 .width() 返回选中元素的宽度, 它是没有连贯性的).使我们的插件方法具有连贯性需要一行代码:

  This works, but there's a couple of things we need to do for our plugin to survive in the reeal world. One of jQuery's features is chaining, when you link five or six actions onto one selector. This is accomplished by having all jQuery object methods return the original jQuery object again(there are few exceptions: .width() called without parameters return the width of the selected element, and is not chainable). Making our plugin method chainable takes one line of code:

$.fn.greenify = function(){
    this.css("color", "green");
    return this;
}
$("a").greenify().addClass("greenified");

  值得注意的是连贯性的概念在类似 $.trim() 的 jQuery 实用函数上不适用.

  Note that the notion of chaining is not applicable to jQuery utility methods like $.trim().

保护$别名和添加范围

Protecting $ Alias and Adding Scope

  变量$在JavaScript库中非常受欢迎,如果你在使用jQuery的同时使用其他的库,你应使用jQuery.noConflict()来使jQuery不使用$.然而,假设$是jQuery函数的别名将损坏我们的插件.我们需要将我们所有的代码放进一个立即调用函数表达式里面, 然后传递函数jQuery,命名为参数$:

  The $ variable is very popular among JavaScript libraries, and if you're using another library with jQuery, you will have make jQuery not use the $ with jQuery.noConflict(). However, this will break our plugin since it is written with the assumption that $ is an alias to the jQuery function. To work well with other plugins, and still use the jQuery $ alias, we need to put all of our code inside of an Immediately Invoked Function Expression, and then pass the function jQuery, and name the parameter $:

(funtion($){
    $.fn.greenify = function(){
        this.css("color", "green");
        return this;
    }
    $.ltrim = function(str){
        return str.replace(/^\s+/, "");
    }
    $.rtrim = function(str){
        return str.replace(/\s+$/, "");
    }
}(jQuery));

  并且,立即调用函数表达式的主要作用是允许我们拥有自己的私有变量.假设我们想添加一个不同的颜色,而且我们想将它保存在一个变量里面.

  in addition, the primary purpose of an Immediately Invoked Function is to allow us to have our private variables. Pretend we want a different color, and we want to store it in a variable.

(function($){
	var shade = "#556b2f";
	$.fn.greenify = function(){
		this.css("color", shade);
		return this;
	}
}(jQuery));

Minimizing Plugin Footprint

  好的惯例是写一个插件只占用 $.fn 的一个接口,这段代码可能导致你的插件被其他的插件覆盖,也可能导致你的插件覆盖了其他插件,换句话说,这是段糟糕的代码:

  It's good practice when writing plugins to only take up one slot within $.fn. This reduces both the chance that your plugin will be overridden, and the chance that your plugin will override other plugins. In other words, this is bad:

(function($){
	$.fn.openpopup = function(){
		//open popup code.
	}
	$.fn.closepopup = function(){
		//close popup code.
	}
}(jQuery));

  使用单接口和使用参数来控制单接口执行什么样的行动将会好得多

  It would be much better to have one slot, and use parameters to control what action that one slot performs.

(function( $ ) {
    $.fn.popup = function( action ) {
        if ( action === "open") {
            // Open popup code.
        }
        if ( action === "close" ) {
            // Close popup code.
        }
    };
}( jQuery ));

使用 each() 方法

Using the each() Method

  你的典型的jQuery对象可能包含任意数量的DOM元素,这也是为什么经常把jQuery对象称为集合的原因.如果你想对特定的元素进行一些操作(例如:读取属性, 计算特定位置),那么你需要使用 .each() 来遍历这些元素.

  Your typical jQuery object will contain references to any number of DOM elements, and that's why jQuery objects are often referred to as collections. If you want to do any manipulating with specific elements (e.g. getting a data attribute, calculating specific positions) then you need to use .each() to loop through the elements.

$.fn.myNewPlugin = function(){
	return this.each(function(){
		//Do something to each element here.
	});
}

  注意我们返回 .each() 代替返回 this. 因为 .each() 已经是具有连贯性的,它的返回值是 this.在我们曾经做过的事中,到目前为止,这是一个维护可连续性更好的办法.

  Notice that we return the results of .each() instead of returning this. Since .each() is already chainable, it returns this, which we then return. This is a better way to maintain chainability than what we've been doing so far.

接受选项

Accepting Options

  当你的插件越来越复杂,好的主意是通过接受一些选项来使你的插件可定制.最简单的做到这一点的办法是一个字面对象,特别是有很多的选项.让我们修改我们的greenify插件以接受一些选项.

  As your plugins get more and more complex, it's a good idea to make your plugin customizable by accepting options. The easiest way do this, especially if there are lots of options, is with an object literal. Let's change our greenify plugin to accept some options.

(function($){
	$.fn.greenify = function(options){
		//This is the easiest way to have default option
		var settings = $.extend({
			//These are the defaults.
			color: "#55b62f",
			backgroundColor: "white"
		}, options);
		//Greenify the collection based on the settings
		return this.css({
			color: setting.color,
			backgroundColor: setting.backgroundColor
		});
	};
}(jQuery));

//Example usage:

$("div").greenify({
	color: "orange"
});

  color 的缺省值 #556b2f 被 $.extend() 覆盖为 orange.

  The default value for color of #556b2f gets overridden by $.extend() to be orange.

把它们放在一起

Putting It Together

  这里是一个使用了一些我们已经讨论过的技巧的小插件例子:

Here's an example of a small plugin using some of the techniques we've discussed:

(function($){
	$.fn.showLinkLocation = function(){
		return this.filter("a").each(function(){
			$(this).append(" (" + $(this).attr("href") + ")");
		});
	};
}(jQuery));

//Example usage:

$("a").showLinkLocation();

  这个易用的插件遍历集合中所有的链接然后把href属性放在括弧中添加在元素后面.

  This handy plugin goes through all anchors in the collection and appends the href attribute in brackets.

  我们的插件可以通过以下代码优化:

  Our plugin can be optimized though:

(function($){
	$.fn.showLinkLocation = function(){
		return this.filter("a").append(function(){
			return " (" + this.href + ")";
		})
	};
}(jQuery));

  我们使用的是 .append() 方法的接受回调函数的能力,返回值将决定集合中的每个元素的尾部添加什么.注意我们不是使用 .attr() 方法来检索href属性,因为原生的DOM API给了我们适当命名的href属性方便使用.

  We're using the .append() method's capability to accept a callback, and the return value of that callback will determine what is appended to each element in the collection. Notice also that we're not using the .attr() method to retrieve the href attribute, because the native DOM API gives us easy access with the aptly named href property.