【翻译】谈 focus 和 blur 的事件代理

在下拉列表等许多常用的效果中,事件代理往往非常的重要,因为许多在各个链接上触发的事件,往往可以很容易的在根节点中进行监听。

然而这会引发一个问题,尽管事件代理对于鼠标事件的响应非常好,但它对于focus和blur事件却不支持。而让键盘操作支持下拉列表往往需要它们来实现。

随后,在我对事件的实验中,我发现了代理focus和blur事件的方法。

什么是事件代理

让我们先讨论一下什么是事件代理。我将用一个下拉菜单来作为我们的例子。

当用户使用鼠标操作下拉菜单时,我们需要监听用户所有的mouseover和mouseout事件,以便判断用户最后一个行为应该打开或是关闭菜单。

mouseover和mouseout事件是会冒泡的。也就是说,当一个mouseover事件在链接上产生时,该事件会在dom树上往上"爬",这样去查看链接的任意父节点是否也定义了mouseover事件。它首先会查看链接自己,随后查看其父节点<li>,接着查看<ol>,接着一直追查到document或者window节点

这意味着我们完全可以将通用的事件监听函数定义在整个菜单的根节点<ol>上。当mouseover,mousedown等事件发生在子结点时,事件的冒泡会保证我们根节点的监听函数能够捕捉到它

 1  < ol id = " dropdown " >
 2       < li >< a href = " # " > List item  1 < / a>
 3           < ol >
 4               < li >< a href = " # " > List item  1.1 < / a>< / li >
 5               < li >< a href = " # " > List item  1.2 < / a>< / li >
 6               < li >< a href = " # " > List item  1.3 < / a>< / li >
 7           < / ol>
 8       < / li>
 9      [etc.]
10  < / ol>
11 
12  $( ' dropdown ' ).onmouseover  =  handleMouseOver;
13  $( ' dropdown ' ).onmouseout  =  handleMouseOut;

 

这个技巧最大的好处是我们不需要在每一个链接上都定义两个事件句柄,从而可以节省浏览器内存消耗。

focus引发的问题

一切都很好。然而,当你需要让你的下拉菜单支持键盘事件的时候,你将遇到麻烦。

理论上说,让下拉菜单支持键盘事件是很容易的:你只需定义好focus事件和blur事件的事件句柄。然而,问题在于,这两个事件并不会冒泡。链接上的focus或blur事件仅发生于链接自身上,而它的任何父节点上的事件都不会产生。

这是一项很古老的规则。少数事件,例如focus,blur,change等,并不会在dom树上冒泡。这样设计准确的原因已经无从考究,但部分原因只是由于这些事件对一些元素来说是没有意义的。用户不可能更改或聚焦于一段随即的段落上。因此这些事件不支持这一些html标签。于是,它们不会发生冒泡了。

看看下面的例子:

1  < p id = " testParagraph " >
2      Some text.
3       < input id = " testInput "   / >
4  < / p>
5 
6  $( ' testParagraph ' ).onfocus  =  handleEventPar;
7  $( ' testInput ' ).onfocus  =  handleEventInput;

 

当用户聚焦于input元素上时,handleEventInput事件将被触发。然而,由于事件并不会冒泡,handleEventPar将不会执行。另外,由于我们不可能聚焦于段落上(除非它定义了tabindex属性),handleEventPar将永远不会被执行。

事件的捕获

除非我们使用事件的捕获。

事件的捕获与事件的冒泡是相反的。事件的冒泡,开始发生与触发事件节点本身,随后在dom树上上行。而事件的捕获,最开始发生于dom树的根节点(通常是document或者window),随后在dom树上下行。

在我实验中,我感到最好奇的是,不论所给定的节点是否对发生的事件有意义,所有的捕获阶段的父节点的事件句柄都会被触发。

所以,让我们做一个类似的实例。但是现在使用addEventListener来添加捕获的事件。

1  < p id = " testParagraph " >
2      Some text.
3       < input id = " testInput "   / >
4  < / p>
5 
6  $( ' testParagraph ' ).addEventListener( ' focus ' ,handleEventPar, true );
7  $( ' testInput ' ).addEventListener( ' focus ' ,handleEventInput, true );

 

现在如果用户聚焦于input元素,事件会在window对象或者document对象上触发,随后一直细化到input元素本身。在这个过程中,他将遇到段落上定义的onfocus句柄并且执行它,即使聚焦事件对于段落来说没有意义。

最终结果,handleEventPar先执行,然后才是handleEventInput。

IE

不幸的是ie不支持捕获事件。然而,它支持focusinfocusout这两个事件。与focus和blur相反,它们支持事件的冒泡。如果我们在ie上使用这些事件,我们就大功完成了。

focus和blur事件的代理

因此,我们的结论是,onfocus和onblur事件都可以通过注册捕获事件来获得onmouseover相同的效果。于是我们可以代理所有的键盘兼容的下拉菜单的事件了。

 1  < ol id = " dropdown " >
 2       < li >< a href = " # " > List item  1 < / a>
 3           < ol >
 4               < li >< a href = " # " > List item  1.1 < / a>< / li >
 5               < li >< a href = " # " > List item  1.2 < / a>< / li >
 6               < li >< a href = " # " > List item  1.3 < / a>< / li >
 7           < / ol>
 8       < / li>
 9      [etc.]
10  < / ol>
11 
12  $( ' dropdown ' ).onmouseover  =  handleMouseOver;
13  $( ' dropdown ' ).onmouseout  =  handleMouseOut;
14  $( ' dropdown ' ).onfocusin  =  handleMouseOver;
15  $( ' dropdown ' ).onfocusout  =  handleMouseOut;
16  $( ' dropdown ' ).addEventListener( ' focus ' ,handleMouseOver, true );
17  $( ' dropdown ' ).addEventListener( ' blur ' ,handleMouseOut, true );

最终效果



ppk的文章总是很经典。这次做项目遇到blur不支持冒泡的问题,又在ppk这里找到了答案。搜不到有翻译的版本,想想对于很多开发者来说这样一个hack是相当有用的,于是自己翻译了出来。ppk写文章的过程中也没有解决ie的问题,后来Dean Edwards在留言中指出了解决方法。乐于分享,共同成长。

转载于:https://www.cnblogs.com/demix/archive/2009/10/15/1584022.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值