attachEvent与addEventListener的区别

12

我在使用attachEvent时遇到了麻烦。在支持addEventListener处理程序的所有浏览器中,下面的代码都可以完美运行,但在IE中却是一场灾难。他们有自己的(不完整的)变体称为attachEvent。

现在问题来了,我如何使attachEvent以与addEventListener相同的方式工作?

这是代码:

function aFunction(idname)
{
    document.writeln('<iframe id="'+idname+'"></iframe>');
    var Editor = document.getElementById(idname).contentWindow.document;

    /* Some other code */

    if (Editor.attachEvent)
    {
        document.writeln('<textarea id="'+this.idname+'" name="' + this.idname + '" style="display:none">'+this.html+'</textarea>');
        Editor.attachEvent("onkeyup", KeyBoardHandler);
    }
    else
    {
        document.writeln('<textarea id="hdn'+this.idname+'" name="' + this.idname + '" style="display:block">'+this.html+'</textarea>');
        Editor.addEventListener("keyup", KeyBoardHandler, true);
    }
}

这会调用名为 KeyBoardHandler 的函数,它看起来像这样:

function KeyBoardHandler(Event, keyEventArgs) {
    if (Event.keyCode == 13) {
        Event.target.ownerDocument.execCommand("inserthtml",false,'<br />');
        Event.returnValue = false;
    }

    /* more code */
}

我不想使用任何框架,因为 A) 我正在尝试学习和理解某些东西,而 B) 任何框架都只是我不会使用的代码过载。

非常感谢您的任何帮助!


你的观点很好,尝试学习不使用框架来理解基于浏览器的JavaScript的内部工作原理。然而,我建议你在掌握了低级JavaScript之后,转向使用框架进行生产代码,因为重复造轮子没有多大意义(框架已经在各种浏览器上进行了广泛测试,一旦你自己编写框架,它将变得非常庞大,以解决浏览器中的怪异问题并避免在代码的其他地方出现样板代码)。此外,外部JavaScript可以被浏览器缓存一次用于多个请求。 - Arc
你想要做什么?目前出现了什么问题? - lincolnk
类似jQuery的框架现在更像是一种标准,它们试图使跨浏览器兼容成为现实,并在您需要执行特定操作并想要完全控制时使用JavaScript。 - Bogdan M.
6个回答

14

以下是如何跨浏览器使其工作的方法,只供参考。

var myFunction=function(){
  //do something here
}
var el=document.getElementById('myId');

if (el.addEventListener) {
  el.addEventListener('mouseover',myFunction,false);
  el.addEventListener('mouseout',myFunction,false);
} else if(el.attachEvent) {
  el.attachEvent('onmouseover',myFunction);
  el.attachEvent('onmouseout',myFunction);
} else {
  el.onmouseover = myFunction;
  el.onmouseout = myFunction;
}

参考资料: http://jquerydojo.blogspot.com/2012/12/javascript-dom-addeventlistener-and.html


7
你的问题源于 KeyBoardHandler 函数。具体来说,在 IE 中,Event 对象没有 target 属性:相当于是 srcElement。此外,Event 对象的 returnValue 属性只在 IE 中有效。你需要在其他浏览器中使用 preventDefault() 方法。
function KeyBoardHandler(evt, keyEventArgs) {
    if (evt.keyCode == 13) {
        var target = evt.target || evt.srcElement;
        target.ownerDocument.execCommand("inserthtml",false,'<br />');
        if (typeof evt.preventDefault != "undefined") {
            evt.preventDefault();
        } else {
            evt.returnValue = false;
        }
    }

    /* more code */
}

2
只需使用jQuery或原型等框架。这就是它们存在的原因:能够做到这种事情而不必担心跨浏览器兼容性。安装非常简单...只需包含一个.js脚本并添加一行代码即可...
使用框架,代码就像这样简单...
<script type='text/javascript' src='jquery.js'></script>
$('element').keyup(function() { 
  // stuff to happen on event here
});

说真的...去学习jQuery或者其他什么东西吧...我曾经抵制它很长一段时间...有一天,我被迫学习了它,以至于修复了一些使用它的代码...从那时起...我不停地责备自己没有早点使用它。这是自面包片以来最伟大的发明。 - CrayonViolent
11
为什么不向OP展示使用jQuery或Prototype有多么容易呢!“只需使用jQuery”并不是什么答案。 - Crescent Fresh
1
开心吗?我没想到一些“超级简单”的东西需要解释,但既然你想像某种互联网警察一样表现得像个驴子...顺便说一句,谢谢你的负评,很高兴让你这位自以为是的人的一天变得更加明亮。 - CrayonViolent
@Crayon,你不知道Crescent Fresh是否真的投了反对票。但我同意,所以给你点赞。 - Pekka
让我们友好相处,没有必要为这么小的事情争吵。;-) - Léon
在Crescent Fresh的辩护中,我对JS还比较新,并且我也在研究这个问题,你的回答并不是一个真正的回答。即使你添加了代码片段,缺乏解释也毫无帮助。只是这么说。 - Mike_OBrien

2

这是我在浏览器中使用的一个函数:

function eventListen(t, fn, o) {
    o = o || window;
    var e = t+Math.round(Math.random()*99999999);
    if ( o.attachEvent ) {
        o['e'+e] = fn;
        o[e] = function(){
            o['e'+e]( window.event );
        };
        o.attachEvent( 'on'+t, o[e] );
    }else{
        o.addEventListener( t, fn, false );
    }
}

你可以像这样使用它:

eventListen('keyup', function(ev){
  if (ev.keyCode === 13){
    ...
  }
  ...
}, Editor)

1
对称起见,detachEvent/removeEventListener的相反操作是什么样子的? - Crescent Fresh
那么在这种情况下,我该如何使用上面的代码?抱歉,我有点 JS 新手。 :/ - Léon
@Mic;不幸的是它不起作用。我可以把整个代码发给你,这样你就能看到目的了吗? - Léon
这是一个在IE和其他浏览器上都能运行的小例子 http://gist.github.com/586091 我会检查你的。 - Mic
在回调函数中,IE与其他浏览器有所不同,例如:event.srcElement,而其他浏览器使用的是event.target。你可能需要像这样抽象出来:var target = ev.target || ev.srcElement。晚安! - Mic
显示剩余4条评论

2

useCapture 只决定事件是在捕获序列还是冒泡序列中触发。IE 只执行冒泡序列,因此为了兼容性使用 false。它不会改变处理程序的过程。 - lincolnk

0

你最好使用JavaScript框架,例如MooToolsjQuery来方便跨浏览器支持。详情请参见

以下是 MooTools 对你的示例代码的部分移植:

var Editor = $(idname).contentWindow.document;
...
$(document.body).grab(new Element('textarea', {
    'id'   : this.idname,
    'name' : this.idname,
    'style': 'display:none;',
    'html' : this.html
});
Editor.addEvent('keyup', KeyBoardHandler);

顺便问一下,你在上面的代码中故意使用了idnamethis.idname两种方式吗?

3
谢谢大家,但不用了。;-) 首先,我正在尝试学习一些东西,其次,我不想要那些我不会使用的代码过载。所以请不要给我任何外部框架方面的建议,虽然我理解这背后的思想。 - Léon
1
我是出于最好的意图说这句话——也许学习高级概念,如回调、承诺、模块模式、柯里化等,而不是了解底层浏览器的怪癖,会更好。随着浏览器变得更加标准化,你学习这些具体细节的投资回报将会降低,而学习更抽象的JavaScript思想同样令人满意,同时为你在其他语言和未来的不同事物中装备自己。 - iono

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接