表单元素常用事件有 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 表单 表单元素 事件委托 事件冒泡