jQuery开发中自定义事件和插件解析

Query 插件的实现深受自定义事件机制的影响,同样,自定义事件也是处理与DOM 产生交互的代码逻辑片段之间耦合的很好的架构方法。

当你想给你的应用添加一个功能片段时,或许经常纠结于是否应当将这个片段抽离为一个插件。自定义事件的思路可以帮你做这种解耦,并逐渐形成一个可复用的库。
  比如,我们来看一个简单的jQuery 插件——选项卡。我们让ul 列表来响应点击事件。当用户点击一个列表项,给这个列表项添加一个名为active 的类,同时将其他列表项中的active 类移除:

双击代码全选

1

2

3

4

5

6

7

8

<ul id="tabs">

<li data-tab="users">Users</li>

<li data-tab="groups">Groups</li>

</ul>

<div id="tabsContent">

<div data-tab="users"> ... </div>

<div data-tab="groups"> ... </div>

</div>

 

  另外,id 为tabsContent 的div 用来存放每个选项卡对应的实际内容。根据当前激活的选项卡,来对应地给div 的子节点添加或删除active 类。实际的显示和隐藏选项卡和内容都由CSS 来控制,我们的插件仅仅处理active 类:

双击代码全选

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

jQuery.fn.tabs = function(control){

var element = $(this);

control = $(control);

element.find("li").bind("click", function(){

// 从列表项中添加或删除 active 类

element.find("li").removeClass("active");

$(this).addClass("active");

// 给tabContent 添加或删除active 类

var tabName = $(this).attr("data-tab");

control.find(">[data-tab]").removeClass("active");

control.find(">[data-tab='" + tabName + "']").addClass("active");

});

// 激活第1 个选项卡

element.find("li:first").addClass("active");

// 返回this 以启用链式调用

return this;

};

 

  插件位于jQuery 的prototype 里,因此可以基于jQuery 实例来调用:
  $("ul#tabs").tabs("#tabContent");
   现在看上去插件有什么问题吗?没错,我们给所有的列表项都添加了click 事件回调,这是第1 个错误。我们可以使用上文提到的delegate() 来优化代码。同样,点击事件回调的实现很臃肿,很难一眼看出发生了什么。除此之外,如果另一个开发者想要扩展这个插件,他很可能会将其重写。
  我们来看下如何使用自定义事件让代码变得更整洁。在点击选项卡时触发一个change.tabs 事件,并绑定若干回调方法来适当修改active 类:

双击代码全选

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

jQuery.fn.tabs = function (control) {

var element = $(this);

control = $(control);

element.delegate("li", "click", function () {

// 遍历选项卡名称

var tabName = $(this).attr("data-tab");

// 在点击选项卡时触发自定义事件

element.trigger("change.tabs", tabName);

});

// 绑定到自定义事件

element.bind("change.tabs", function (e, tabName) {

element.find("li").removeClass("active");

element.find(">[data-tab='" + tabName + "']").addClass("active");

});

element.bind("change.tabs", function (e, tabName) {

control.find(">[data-tab]").removeClass("active");

control.find(">[data-tab='" + tabName + "']").addClass("active");

});

// 激活第1 个选项卡

var firstName = element.find("li:first").attr("data-tab");

element.trigger("change.tabs", firstName);

return this;

};

 

  我们看到使用自定义事件回调可以让代码更加整洁。这也意味着选项卡状态切换回调彼此分离,这也让插件代码更具扩展性。比如我们可以在程序中直接更改选项卡的状态,只需触发被观察列表的change.tabs 事件即可:
  $("#tabs").trigger("change.tabs", "users");
  同样,我们可以将切换选项卡的动作和窗口的hash 做关联,这样就可以使用浏览器的后退按钮了:

双击代码全选

1

2

3

4

5

6

7

$("#tabs").bind("change.tabs", function(e, tabName){

window.location.hash = tabName;

});

$(window).bind("hashchange", function(){

var tabName = window.location.hash.slice(1);

$("#tabs").trigger("change.tabs", tabName);

});

 

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Grow your business fast with

Suku