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插件的问题:

  1. 关于开头的;:js代码结束的时候,最后一句是允许不加分号的(比如一个函数的最后一句).如果某个js代码这么做了,那么把它跟另外一个js脚本拼在一起的时候,原来是”最后一句”的,变成了不是最后一句,于是就出现语法错误了.
  2. 关于这个IIEF:用IIEF的好处在于利用闭包的特性,把功能的实现放在闭包中,避免了内部变量影响全局空间.同时通过传入jQuery对象,在内部可以$作为jQuery的别名.
  3. jQuery插件命名:jquery.myPlugin.js
  4. 注意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)
  5. 注意jQuery pulugin要保持jquery一贯的chainable的特性(虽然我知道很多人从来不用jQuery的链式调用)
    说到底jQuery之所以可以链式调用,就是因为jQuery每次方法调用都把自己的jQuery对象返回出来了,从第4点我们可以想到,想要jQuery plugin还能保持链式调用就需要在函数执行完毕把this(当前jQuery对象)返回出来就可以了.

  6. 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
    34
    var 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)

    两种方式的使用对比:
    jquery_plugin_extend.png
    jquery_plugin_extend1.png
    可以发现第一种写法会污染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);