文章目录
  1. 1. 简介
  2. 2. 举例说明
    1. 2.1. $.widget()
    2. 2.2. _create()
    3. 2.3. this.element 和 绑定事件
    4. 2.4. 接受部件选项
    5. 2.5. 启用和禁用插件
    6. 2.6. 触发部件事件
    7. 2.7. 销毁部件
    8. 2.8. 公共子方法
    9. 2.9. others
  3. 3. QA

用 jQuery 编写第三方插件,常见的三种方式:

  1. 新的全局函数 $.xxx()
  2. jQuery 的对象方法 $(‘div’).xxx()
  3. jQuery UI 的部件工厂:少量编码,复杂插件

前两种方式在上节 《用 jQuery 编写第三方插件》 中有介绍到,本节重点关注第3点:jQuery UI 的部件工厂。

简介

jQuery UI 提供了一套部件。部件本身就是插件,只不过是用来生成特定的 UI 元素,它有一组非常统一的 API。如果我们想要编写自己的插件,且该插件会创建新的用户界面元素,那么此时,最好是以扩展 jQuery UI 库的方式来实现。

jQuery UI 库的核心包含了一个工厂方法 $.widget(),这个方法为我们做了很多事情,以确保我们的代码达到所有 jQuery UI 部件共享的 API 标准。 使用部件工厂创建的插件,自带以下功能,包括但不限于:
1.插件具有的状态:可以检测、修改,甚至在应用之后完全颠覆插件的原始效果
2.自动将用户提供的选项和定制的选项合并到一起
3.多个插件方法无缝组合成一个 jQuery 方法,这个方法接受一个表明要调用哪个子方法的字符串
4.插件触发的自定义事件处理程序,可以访问部件实例的数据

举例说明

在本小节中,我们通过代码实例,来认识下 jQuery UI 部件的相关特性:
1.通过部件工厂创建插件 $.widget()
2.插件的初始化函数 _create()
3.触发插件的元素:引用、绑定事件
4.部件选项:默认、接收、覆盖
5.插件状态:启用&禁用、销毁插件
6.触发部件事件
7.添加插件的方法:私有方法、公有方法

首先,要在页面里引用这三个 js:jquery、jquery.ui.core 和 jquery.ui.widget,因为 jQuery UI 依赖于它们

1
2
3
4
<script src="http://s0.qhimg.com/lib/jquery/183.js"></script>
<!--包括:jquery.ui.core 和 jquery.ui.widget-->
<script src="http://s1.qhimg.com/!1a14ec34/js/jquery-ui-1.10.3.custom.js"></script>

现在,我们要实现一个为元素添加自定义提示条的 UI 插件。待完成的是功能是:
1.为元素创建一个div容器
2.当鼠标悬停在该元素上时,把这个容器放在相应元素的旁边。
代码如下:

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
58
59
60
61
62
63
64
65
66
67
(function($){
//1. 通过部件工厂创建插件 $.widget()
$.widget('ljq.tooltip', {
//2. _create() 特殊的函数【相当于"初始化函数"】
_create: function(){
//将创建元素的引用保存在this._tooltipDiv中,以备将来使用
this._tooltipDiv = $('<div></div>')
.addClass('ljq-tooltip-text ' +
'ui-widget ui-state-highlight ui-corner-all')
.hide().appendTo('body');
//3. this.element 和 绑定事件
this.element
.addClass('ljq-tooltip-trigger')
.bind('mouseenter.ljq-tooltip', $.proxy(this._open, this))
.bind('mouseleave.ljq-tooltip', $.proxy(this._close, this));
},
//4. 接受部件选项
options: {
offsetX: 0,
offsetY: 0,
content: function(){
return $(this).data('tooltip-text');
}
},
_open: function(){
//5. 启用和禁用插件
if(!this.options.disabled){
var elementOffset = this.element.offset();
this._tooltipDiv.css({
left: elementOffset.left + this.options.offsetX,
top: elementOffset.top + this.element.height() + this.options.offsetY //取选项options中的值
}).text( this.options.content.call(this.element[0]) );
this._tooltipDiv.show();//?为何不链式调用.show呢
//6. 触发部件事件
this._trigger('open');
}
},
_close: function(){
this._tooltipDiv.hide();
this._trigger('close');//6. 触发部件事件
},
//7. 销毁部件
distory: function(){
this._tooltipDiv.remove();
this.element
.removeClass('ljq-tooltip-trigger')
.unbind('.ljq-tooltip');
$.widget.prototype.destroy.apply(this, arguments);
},
//8. 添加子方法-公共的
open: function(){
this._open();
},
close: function(){
this._close();
}
});
})(jQuery);

使用插件时:

1
2
3
4
5
6
7
8
9
10
11
//不传参
$('a').tooltip();
//用参数调用
$('a').tooltip({
offsetX: 200,
offsetY: 200,
});
//子方法们
$('a').tooltip('open').tooltip('close').tooltip('distory');

接下来,我们来逐个认识下代码中的相关知识点:

$.widget()

通过部件工厂创建插件,它接收两个参数:

  1. 部件的名字,即”ljq.tooltip”:部件的名字必须带有命名空间,此例中”ljq”是命名空间,”tooltip”是插件名
    使用时,直接在 jQuery 对象上调用 .tooltip(),和插件的名字保持一致。
  2. 部件属性的映射:它可以是选项对象,也可以是函数。当函数名以下划线_开头时,代表是私有函数。否则是公有函数

_create()

_create() 是个特殊的函数,每当 jQuery 对象中每个匹配的元素调用 .tooltip() 时,部件工厂就会调用它。

this.element 和 绑定事件

this.element 存了一个 jQuery 对象,这个对象指向最初选择的元素,我们用 this.element 给提示条的触发元素绑定事件。
绑定事件时,事件名也要加上和插件名一样的命名空间前缀,即 “mouseenter.ljq-tooltip”。此处,把处理程序传递给 $.proxy(this._open, this),这个函数会修改 this 的指向,因此才能在 _open 函数中引用部件的实例。

接受部件选项

让部件可定制:在之前介绍的 .shadow() 插件中,我们已经为部件提供了一组定制的默认值,用户也可以用指定的选项去覆盖默认值。在这里呢,我们可以“清闲”点不用那么麻烦,因为几乎所有的工作都是由部件工厂执行的,我们要做的就是:提供一个 options 属性。
options 属性是一个映射,包括插件所需的所有选项,这样用户就可以不用提供了-直接用默认值即可。在插件内的子方法中,可以通过 this.options 来访问这些选项。而且,通过这种方式访问选项,始终都能保证取得的是正确的值-即要么是默认,要么是用户提供的覆盖了默认值。

启用和禁用插件

插件,除了被完全销毁外,还可以临时禁用-然后在将来重新启用部件。内置的 enable 和 disable 子方法,可以帮助我们实现部件的启用和禁用,即 .tooltip(‘enable’) 和 .tooltip(‘disable’)。它们是分别给 this.options.disabled 赋了不同的值,即 this.options.disabled = true|false; 要支持这两个子方法,我们只需要做:对部件进行任何操作前,先检查这个值,就 ok 了。

触发部件事件

真正的好插件,除了自己可以扩展 jQuery 外,还可以为其他代码提供机制来扩展它。提供这种扩展能力的方法之一,就是:支持与插件相关的一组自定义事件。
this._trigger(‘open’) 可以让代码监听新的自定义事件,在这个元素上调用 .bind(‘tooltipopen’) 就可以监听这个事件。监听时的事件命名是”部件名字+事件名字”,所以不会与外界的事件名冲突。

销毁部件

部件工厂可以创建新的 jQuery 方法,上面的代码就创建了 .tooltip()。可以给这个方法传入一个字符串参数,就可以调用适当的子方法了。其中,销毁部件的内置子方法是 destroy,所以,调用 .tooltip(‘destroy’) 就可以从页面中删除这个提示条部件,部件工厂为我们做了很多工作。
但,如果我们通过 _create() 修改了文档(即创建了新的div),那么在销毁之前,我们自己要负责将其清理掉。然后再调用保存在原型对象中的 destory,便会自动完成清理工作。

公共子方法

创建私有函数,函数名以下划线开头,即可
创建公有函数,函数名不以下划线开头,即可

在公有函数(即子方法)里,里面什么都不返回,部件工厂也会默默地做好多工作,从而确保连缀语法可以正常工作。比如,我们可以这样使用 .tooltip(‘open’) .tooltip(‘close’)

others

1.this:在部件内部的上下文中,this 引用当前部件实例,可以用它来为部件添加任何想要的属性
2.部件实例本身,也有一些预定义的属性可供我们使用。比如 this.options、this.options.disabled、this.element 等
这个插件本身不复杂,代码也不长。但它却浓缩了很多高级概念。

QA

??
每个部件都有哪些复杂性
jQuery UI 库都有什么必须的共享API标准
触发部件事件,它的应用场景是啥,意思是:_trigger()了之后 才能那么bind么?
this.options.content.call(this.element[0])

this.element “最初选择的元素”还是触发提示条的那个元素么…如果是.find().find()
?为何不链式调用.show呢?是考虑到上面操作了css和text-生效后才show?or 笔误?

那个…
事实上,这个功能很诱人,在构建任何适当的(无论是否与UI相关)复杂插件,谁都希望使用部件工厂的方法。“都希望” 是么?但它又需要额外引入 jquery.ui.core 和 jquery.ui.widget 呢…感觉这两种不同的创建插件的方法,各有自己的适用场景吧。自己抽取几个实战感受下。

链式调用棒棒哒
公用的方法不用返回什么 就自动连缀。【果然做了挺多的】

文章目录
  1. 1. 简介
  2. 2. 举例说明
    1. 2.1. $.widget()
    2. 2.2. _create()
    3. 2.3. this.element 和 绑定事件
    4. 2.4. 接受部件选项
    5. 2.5. 启用和禁用插件
    6. 2.6. 触发部件事件
    7. 2.7. 销毁部件
    8. 2.8. 公共子方法
    9. 2.9. others
  3. 3. QA