表单元素常用事件有 change、select、submit、reset,他们在 Document Object Model Events 规范中均被标注为可冒泡(Bubbles: Yes)。
IE6 IE7 IE8 IE9(Q) 中 change、select、submit、reset 事件均不产生事件冒泡。
如果将事件处理委托给产生这些事件的父元素或祖先元素处理,在 Chrome Safari Firefox 中均是没有问题的。但是由于 IE6 IE7 IE8 中这些事件不产生事件冒泡,将会导致位于祖先元素的事件委托没有被执行,可能会导致错误数据提交或页面UI不正常等情况出现。
| IE6 IE7 IE8 IE9(Q) |
|---|
最早的 DOM Level 2 Event Model 版本为 1999 年 3 月成文,变更至今日均指定了 change、select、submit、reset 事件均可产生事件冒泡:
规范的成文时间已经涵盖了 IE6 开发时间,因此可以基本推断早期的 IE 版本如果遵循了此规范,那么事件将会冒泡到祖先元素上。
事实是否如此呢?我们看一组测试用例:
<!DOCTYPE html> <html> <head> <script> window.onload = function() { var
addEvent = (document.addEventListener) ? (function(el, type, fn) { el.addEventListener(type, fn, false);
}) : (function(el, type, fn) { el.attachEvent('on' + type, fn) }); var stopDefault = function(e) {
(window.event) ? window.event.returnValue = false : e.preventDefault(); }; var output = function (msg) {
pElement.innerHTML += msg + '<br />'; }; var addOutputMessageByTargets = function(targets,
targetNames, targetEventNames) { for (var i = 0, c = targets.length; i < c; ++i) { for (var j = 0,
len = targetEventNames.length; j < len; ++j) { addEvent(targets[i], targetEventNames[j],
(function(targetName, eventName) { return function(event) { if (targetName === 'HTMLFormElement'
&& eventName === 'submit') { stopDefault(event); } output(targetName + ' triggered ' + eventName
+ ' event.'); } })(targetNames[i], targetEventNames[j]) ); } } }; var pElement =
document.getElementsByTagName('p')[0]; var divElement = document.getElementsByTagName('div')[0]; var
formElement = document.getElementsByTagName('form')[0]; var inputTextElement =
document.getElementsByTagName('input')[0]; var inputCheckboxElement =
document.getElementsByTagName('input')[1]; var inputRadioElement =
document.getElementsByTagName('input')[2]; var selectElement =
document.getElementsByTagName('select')[0]; var textareaElement =
document.getElementsByTagName('textarea')[0]; var clearMessageElement =
document.getElementsByTagName('button')[0]; addOutputMessageByTargets( [window, document, document.body,
divElement], ['DOMWindow', 'Document', 'HTMLBodyElement', 'HTMLDivElement'], ['submit', 'reset',
'change', 'select'] ); addOutputMessageByTargets( [formElement], ['HTMLFormElement'], ['submit',
'reset'] ); addOutputMessageByTargets( [ inputTextElement, inputCheckboxElement, inputRadioElement,
selectElement, textareaElement ], [ 'HTMLInputElement type is text', 'HTMLInputElement type is
checkbox', 'HTMLInputElement type is radio', 'HTMLSelectElement', 'HTMLTextareaElement' ], ['change'] );
addOutputMessageByTargets( [inputTextElement, selectElement, textareaElement], [ 'HTMLInputElement type
is text', 'HTMLSelectElement', 'HTMLTextareaElement' ], ['select'] ); addEvent(clearMessageElement,
'click', function() { pElement.innerHTML = ''; }) }; </script> </head> <body>
<div> <h3>Place change From: </h3> <form> <input type="text"/>
<br /> <input type="checkbox" /> <br /> <input type="radio"
name="radio"/> <br /> <select> <option>1</option>
<option>2</option> </select> <br /> <textarea></textarea> <br
/> <input type="submit" value="submit" /> <input type="reset"
value="reset"/> </form> </div> <h3>output message: </h3>
<p></p> <button>clear message</button> </body> </html>
用例中,我们将这些表单事件依次委托绑定给他们的父元素 DIV、祖先元素 BODY、以及位于事件冒泡顶层的 window 与 document 对象。
如果事件可冒泡,则我们将看到 DIV、BODY、document 与 window 均会在输出事件触发信息。反之,则可看到,仅触发事件的元素自身发出了事件消息。同时,还可以根据消息输出判断出是否有事件没有按照 DIV、BODY、Document、Window 的轨迹向上冒泡执行。
各浏览器中事件冒泡表现如下:
| IE6 IE7 IE8 IE9(Q)1 | IE9(S)2 Firefox Chrome Safari Opera | |
|---|---|---|
| change 事件 | 不冒泡 | 可冒泡至 window |
| select 事件 | 不冒泡 | 可冒泡至 window |
| submit 事件 | 不冒泡 | 可冒泡至 window |
| reset 事件 | 不冒泡 | 可冒泡至 window |
【注1】:IE9(Q) 基本上是模拟 IE5.5 的整体表现方式,因此同样没有遵循规范中指定的事件冒泡规则。
【注2】:IE10 平台预览版第二版的标准文档模式与 IE9(S) 表现一致,事件均可冒泡,由于此篇成文时为非正式版本,故仅做提示而不入上表。
如上表所示,IE6 IE7 IE8 IE9(Q) 版本浏览器中 change、select、submit、reset 事件均不产生事件冒泡,导致其冒泡路径上的事件委托均没有被正常执行。
此现象说明 IE6 IE7 IE8 IE9(Q) 的 change、select、submit、reset 事件事实上都没有参照规范定义产生事件冒泡。
【注】:如果仅从直觉上来判断 IE6-8 的此部分处理是符合使用者预期的,这些事件应如同 focus、blur 事件一样不产生冒泡更合理。但是,考虑到可以触发这些事件的元素基本上都不可以被嵌套,那么规范如此定义将会为事件处理带来更大的灵活性。
为了兼容低版本的 IE 浏览器,建议 change、select、submit、reset 事件均不要依赖事件冒泡机制委托给其祖先元素处理。
| 操作系统版本: | Windows 7 Ultimate build 7600 |
|---|---|
| 浏览器版本: |
IE6
IE7 IE8 IE9 Firefox 6.0 Chrome 16.0.891.0 dev-m Safari 5.1(7534.50) Operea 11.51 |
| 测试页面: |
form_elements_event_bubbles_test.html
|
| 本文更新时间: | 2011-09-27 |
change select submit reset input textarea form 表单 表单元素 事件委托 事件冒泡