Delegating the focus and blur events
这是Peter-Paul Koch写的一篇文章
Delegating the focus and blur events
原文出自:http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
我的翻译:
委托focus和blur事件
现在很多JavaScript编写者们都已经了解到了事件委托的好处。Chris Helimann和Dan Webb曾论述过它的优势,我也在最近两年经常使用到它。
事件委托在一些情况下尤其有用,比如下拉菜单中,当我们直接在根节点上(一个<ol>或<ul>)注册事件将会比为每个链接注册事件简单很多。
但这里有个问题:尽管事件委托对鼠标事件来说能有效使用,但是对于focus和blur事件会失去作用,比如当我们制作一个键盘可访问的下来菜单时。
在我对事件研究的过程中,我发现了一种可以对focus和blur事件进行委托的方法。或许一个非常聪明的JavaScript库作者将会使用这种技术来减少几毫秒的计算时间。
就我所知,他们已经意识到了这种方法,但是对我来说,是一种新方法,所以我把它发布出来了。
例子:
什么是事件委托?
这里简单描述一下,为了那些不知道的人,我用一个下拉菜单来说明。
当一个用户使用鼠标来操控下拉菜单时,你会想捕获所有鼠标悬停和鼠标离开事件,为了知道用户的最后一个动作是要关闭还是打开菜单。(你也必须注意区分有用和无用的事件,因为firefox,safari,opera仍然不支持mouseenter和mouseleave事件,但这是另一个故事了)。
mouseover和mouseout事件都会冒泡;当mouseover事件在一个链接上触发时,这个事件将会沿着DOM树向上,去查找这个节点的那些祖先元素有没有定义mouseover事件。它首先会检查它自身,然后检查包含它的<li>,接着就是<ol>等直到document或者window。
这意味着你可以定义 onmouseover和onmouseout事件函数在像下拉菜单<ol>这样的根元素上,当事件在DOM树深层元素上触发时,事件冒泡可以冒泡到这个根元素上并执行函数。
<ol id="dropdown">
<li><a href="#">List item 1</a>
<ol>
<li><a href="#">List item 1.1</a></li>
<li><a href="#">List item 1.2</a></li>
<li><a href="#">List item 1.3</a></li>
</ol>
</li>
[etc.]
</ol>
$('dropdown').onmouseover = handleMouseOver;
$('dropdown').onmouseout = handleMouseOut;
这样的好处是你不必为每个a链接注册两个函数,还能节省一点浏览器内存。
focus的问题
这个事件本身没问题,但是,一旦你想让你的下拉菜单也能被键盘访问,你就会遇到一个问题。
理论上,做出一个键盘可访问的下拉菜单很容易:你只需要为focus和blur事件注册函数。问题是这两个事件不会冒泡。一个链接的focus或blur事件只会触发它自身,不会触发它的祖先元素。
这是一个古老的规则,有一些事件,比如focus、blur、change都不会冒泡。准确的原因在发展历史中一直都模糊不清。但是部分原因是因为这些事件对有些元素不会起作用。用户不能让一个段落获得焦点或者发生改变。因此,这些HTML元素不能设置这些事件。此外,它们也不能冒泡。
请看下面这个例子:
<p id="testParagraph">
Some text.
<input id="testInput" />
</p>
$('testParagraph').onfocus = handleEventPar;
$('testInput').onfocus = handleEventInput;
当用户在文本框上获得焦点时,handlerEventInput函数会被执行,但是,这个事件不会冒泡,所以handlerEventPar不会执行。另外,不可能对一个段落获得焦点(除非他又一个tabindex的属性),所以handlerEvenPar绝对不会执行。
事件捕获
解决这个问题除非你用事件捕获。
事件捕获恰好和事件冒泡相反。事件冒泡是从目标元素向上沿着DOM树移动。当一个事件被捕获时,它从DOM树的顶层开始(通常是window和document)向下传播一直到目标元素。
在我的事件研究中让我最困惑的结果是,当你在事件捕获阶段定义事件函数时,浏览器将会在目标元素的祖先元素上执行所有事件函数,不管这个事件对这个目标元素能不能作用。
来让我们看一些例子,我们用addEventListner,并在事件捕获阶段调用事件处理程序。(把最后一个参数设置为true)
<p id="testParagraph"> Some text. <input id="testInput" /> </p>$('testParagraph').onfocus = handleEventPar; $('testInput').onfocus = handleEventInput;$('testParagraph').addEventListener('focus',handleEventPar,true); $('testInput').addEventListener('focus',handleEventInput,true);
现在如果你让input获得焦点,这个事件会从window或者document开始向下移动到input,传播过程中,将会途径段落,并在段落上调用这个函数,尽管onfocus事件对段落本来是不起作用的。
因此,handleEventPar会执行,然后handleEventInput再执行。
IE
不幸的是,IE并不支持事件捕获,但它支持另外两个focusin和foucusout事件,这两个事件会冒泡。如果我们在IE中用这两个事件作为上船的准备,我们就可以准备航行了。
委托focus和blur事件
因此,结论就是,要想让focus和blur事件委托像mouseover和mouseout那样,就必须在捕获阶段,为他们注册处理程序。为了正确的给一个可键盘访问的下拉菜单进行事件委托,你应该这样做:
<ol id="dropdown">
<li><a href="#">List item 1</a>
<ol>
<li><a href="#">List item 1.1</a></li>
<li><a href="#">List item 1.2</a></li>
<li><a href="#">List item 1.3</a></li>
</ol>
</li>
[etc.]
</ol>
$('dropdown').onmouseover = handleMouseOver;
$('dropdown').onmouseout = handleMouseOut;
$('dropdown').onfocusin = handleMouseOver;
$('dropdown').onfocusout = handleMouseOut;
$('dropdown').addEventListener('focus',handleMouseOver,true);
$('dropdown').addEventListener('blur',handleMouseOut,true);
这样你就可以成功的委托blur和focus事件了。
posted on 2015-10-30 20:52 daydreamer_xyf 阅读(169) 评论(0) 收藏 举报
浙公网安备 33010602011771号