1. 问题
如果大家看过北风网CJ讲师的Javascript视频教程,就可以看到其封装了一个很强的事件添加和删除函数,如下所示
1 function addEvent(obj, evtype, fn) { 2 //符合W3C的事件模型 3 if (obj.addEventListener) { 4 obj.addEventListener(evtype,fn,false); 5 return obj; 6 } 7 8 //IE或Opera浏览器 9 if (!obj.functions) obj.functions={};10 if (!obj.functions[evtype])11 obj.functions[evtype] = [];12 13 var functions=obj.functions[evtype];14 for (var i=0;i
它因为各种原因,没有采用IE的DOM2级事件添加函数attachEvent,以期达到非常完美的兼容性,据说可以到 IE5.5 或以下。分析代码页可以看到,它通过给DOM元素添加一个以 on + ‘type’ 为名的属性,其对应的值是一个处理函数的数组,本质来说就是仅仅利用 DOM0级提供的接口 elem.onclick = function () { ...} 来添加事件。
一直以来没有发现什么问题,直到给别人使用时,发现IE6~8通过该封装函数 addEvent 添加的 load 事件并没有执行,调试代码发现别人在 JS 中通过 window.onload 赋了一个处理函数,顿时明白这种 addEvent 封装的一个大Bug,原因很简单,通过DOM0级提供的事件接口多次添加时,后面的函数会覆盖前面的,而这种 addEvent 本质上就是一个 DOM0级函数,所以肯定会被后面的覆盖。
也就是说, addEvent 是假定网页JS代码中不使用 DOM0级添加事件。
2. 构建测试页面和代码
1 2 3 4 5 6测试DOM0级事件和DOM2级事件的堆叠 7 8 9 10 11 12 13 43 44
测试1:点击测试按钮,可以看到textarea 中只是输出 DOM 0 Level Click 22222 信息,也就是后面添加的事件覆盖了之前添加的,跟变量赋值是一个道理!!
测试2:将 DOM2 级事件添加的代码反注释掉,打开网页点击测试按钮,可以看到会输出 DOM 2 Level Click 和 DOM 0 Level Click 22222,也就是说DOM0 级事件和 DOM2 级添加的事件都会处理,DOM0级并不会覆盖 DOM2 添加的事件处理函数。
测试3: 将 DOM2 级事件保持注释状态,反注释掉 addEvent 部分, 可以看到只会输出 DOM 0 Level Click 22222。
测试4: 在测试3 的基础上, 注释掉后面两个 DOM0 级添加事件的代码,以测试 addEvent 的输出,可以看到它输出 DOM 2 Level Click, 从而证明测试3中其被覆盖的结论。
3. 总结
1) DOM0 级事件和 DOM2 级事件可以共存;
2) 尽量不要写 DOM0 级事件,特别是代码提供给别人使用时,绝对不能写!