动手写一个jQuery插件
jQuery插件类型
通过
$.extend()
向jQuery添加新的方法
常见用法:$.myPlugin()
.比较典型的有$.ajax()
定义形式及调用方法如下所示:1
2
3
4
5
6
7
8
9
10
11
12
13
14$.extend({
myPlugin : function(a, b){
return a + b;
}
})
//等价为
$.myPlugin = function(a, b){
return a + b;
}
//上面两种形式都是给$增加了一个方法
//调用
$.myPlugin(1, 2)//3通过
$.fn.extend()
扩展jQuery对象实现的插件
常见用法:$("#id").myPlugin()
定义形式及调用方法如下所示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15$.fn.extend({
myPlugin : function(){
// 注意这里this指向 jQuery对象,比如调用者是$('body'),那么this就指向$('body')
console.log(this);
}
})
//等价为
$.fn.myPlugin = function(){
console.log(this);
}
//上面两种形式都是给$('#id')增加了一个方法
//调用
$('body').myPlugin();//[body, prevObject: jQuery.fn.jQuery.init[1], context: document, selector: "body"]
jQuery插件基本形式
写jQuery插件的基本形式依赖一个IIFE
(Immediately-Invoked Function Express)( JS中很多的feature都是结合IIFE和闭包完成的 )
一个基本的jQuery插件形式如下:1
2
3;(function ($) {
/*插件代码*/
})(jQuery);
关于jQuery插件的问题:
- 关于开头的
;
:js代码结束的时候,最后一句是允许不加分号的(比如一个函数的最后一句).如果某个js代码这么做了,那么把它跟另外一个js脚本拼在一起的时候,原来是”最后一句”的,变成了不是最后一句,于是就出现语法错误了. - 关于这个
IIEF
:用IIEF的好处在于利用闭包的特性,把功能的实现放在闭包中,避免了内部变量影响全局空间.同时通过传入jQuery对象,在内部可以$作为jQuery的别名. - jQuery插件命名:
jquery.myPlugin.js
注意
jQuery.fn.extend
这种往jQuery对象上增加方法的时候的this
到底是jQuery元素还是DOM元素1
2
3
4
5
6
7
8
9
10;(function($){
$.fn.myPlugin = function(){
//这里的this是jQuery元素
this.toggle('normal',function(){
//这里的this是DOM元素
//这点跟jQuery对象上调用方法很像,执行jQuery方法,callback中的this指向当前的DOM元素
})
}
})(jQuery)注意jQuery pulugin要保持jquery一贯的
chainable
的特性(虽然我知道很多人从来不用jQuery的链式调用)
说到底jQuery之所以可以链式调用,就是因为jQuery每次方法调用都把自己的jQuery对象返回出来了,从第4点我们可以想到,想要jQuery plugin还能保持链式调用就需要在函数执行完毕把this(当前jQuery对象)
返回出来就可以了.jQuery plugin 默认配置及用户自定义配置(使用
$.extend()
)
在jQuery插件实际使用中,我们会设置一个默认配置default,同时会让用户传入一个配置options,需要当用户不传某些属性参数,就使用默认的参数.我们可以使用jQuery中的extend方法.$.extend()
只包含一个参数的的时候,这个参数会append到jQuery上去,上面所谓的给jQuery扩展方法、属性就是这个方法.$.extend()
包含多个参数的时候,如$.extend(object1, object2, object3)
这个时候object2,object3会合并到object1上面去,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34var object = jQuery.extend({},
{name:'obj1',password:'pwd1'},
{name:'obj2',password:'pwd2'});
//Object {name: "obj2", password: "pwd2"}
//使用jQuery.extend()合并default配置与用户自定义的options配置
;(function($){
var defaults = {
'selector': this,
'delay': 100,
};
$.fn.myPlugin = function(options){
console.log(defaults);
$.extend(defaults, options);
console.log(defaults);
}
})(jQuery)
//上面的写法不是很好,原因在于这样会破坏defaults
//比如$('#id').myPlugin(options),第二次调用的时候defaults是第一次改变的defaults
//相对好一点的写法
;(function($){
var defaults = {
'selector': this,
'delay': 100,
};
$.fn.myPlugin = function(options){
console.log(defaults);
options = $.extend({}, defaults, options);
console.log(defaults);
console.log(options);
}
})(jQuery)两种方式的使用对比:
可以发现第一种写法会污染defaults配置,而第二中写法并不会污染defaults配置
jQuery插件(type writer)
整个type writer的效果如下
代码的github地址:https://github.com/warjiang/simpletypewriter
插件的核心部件如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57;(function($){
//默认配置
var defaults = {
'selector': this,
'delay' : 100,
'str_arr': ['每段時刻的選擇影響','往往造就了無法想像的結局','也謝謝當下的選擇造就了這段愛情',]
};
//在jQuery对象上添加一个typewriter方法
//调用方式$("#id").typewriter(options);
//options
// delay 控制字符显示时间间隔(ms)
// str_arr 字符串数组(需要与selector的元素个数对应起来)
$.fn.typewriter = function(options){
//合并用户配置与默认配置
options = $.extend({length:this.length}, defaults, options);
//对一行不断打印0~i之间的字符串
//这里用了递归的promise是为了控制多行显示
//只有上一行的promise resolve了,才能开启下一行的promise并显示字符
//这里的promise用了jQuery中的defer对象
function type_next_character(element,str,i){
var dfd = $.Deferred();
var t = setInterval(function(){
if(str.length >= i){
//console.log(str.substr(0, i));
element.html(str.substr(0, i));
}
else{
//console.log('clear timer');
clearInterval(t);
dfd.resolve();
}
i++;
},options['delay'])
return dfd.promise();
}
//递归打印下一个jQuery元素
function type_next_element($element,i){
type_next_character($element,options['str_arr'][i],0)
.then(function(){
//用options['length']判断还有没有后续的jQuery元素需要打印
options['length']--;
if(options['length'] > 0){
return type_next_element($element.next(),i+1);
}
});
}
//触发第一行的打印效果
type_next_element(this.first(),0);
//维持chainable特性,把this返回出去,持续链式调用
return this;
}
})(jQuery);