IE中的事件处理

Den*_*tor 2 javascript event-handling javascript-events

我有下面的代码,允许我在用户第一次将鼠标悬停在元素上然后删除事件时执行某些操作.

它在W3C事件模型浏览器中运行良好,但在IE6-8中不断抛出错误.我从另一个问题得到了代码,并相信它会处理IE.有谁看到我做错了什么?

    <script type="text/javascript">
    function setMouseEvent() {
        //Tel: 01 8279 400
        event = addEvent(document.getElementById('contactButton'), 'mouseover', changeText);
    }

    function changeText() {
        alert("worked!");
        removeEvent(document.getElementById('contactButton'), 'mouseover', changeText);
    }

    function addEvent(obj, type, fn) {
        if (typeof obj.addEventListener != undefined) {
            obj.addEventListener(type, fn, false);
        }
        else if (typeof obj.attachEvent != undefined) {
            obj.attachEvent("on" + type, fn);
        }
    }

    function removeEvent(obj, type, fn) {
        if (typeof obj.addEventListener != undefined) {
            obj.removeEventListener(type, fn, false);
        }
        else if (typeof obj.attachEvent != undefined) {
            obj.detachEvent("on" + type, obj[type + fn]);
            obj[type + fn] = null;
            obj["e" + type + fn] = null;
        }
    }

    window.onload = setMouseEvent;
</script>
Run Code Online (Sandbox Code Playgroud)

更新:我刚刚在最新的Chrome,Opera和FF中进行了测试,没有任何问题,但是当鼠标悬停时,Safari没有做任何事情,IE正如上所述抛出错误.

bob*_*nce 6

event = addEvent(
Run Code Online (Sandbox Code Playgroud)

addEvent不归还任何东西; 你将undefined缺乏回报值分配给一个全局变量event(因为你没有var event在函数中说过).这将导致IE中的异常,它使用全局event作为特殊对象将事件详细信息传递给处理程序,因此不允许您为其分配其他内容.

if (typeof obj.addEventListener != undefined)
Run Code Online (Sandbox Code Playgroud)

typeof总是返回一个字符串,它永远不会测试等于undefinedunvalue,因此IE将始终采用非IE分叉并失败.你的意思是if (typeof obj.addEventListener !== 'undefined'),用一个字符串.

obj.detachEvent("on" + type, obj[type + fn]);
Run Code Online (Sandbox Code Playgroud)

由于您没有在函数中编写具有名称typefn粘在一起的属性addEvent,因此无法检索任何内容.

正如Crescent所说,看起来你正在使用Resig的removeEvent功能,与addEvent不匹配的不同搭配.如果你使用他,removeEvent你将需要使用他addEvent去使用它.

但是,我还是不会使用这些功能:它们非常狡猾.我知道这是2005年这个构思错误的代码'赢得'quirksmode的addEvent比赛,但即便如此,我们应该知道更多.问题是它从事件名称和函数code(type+fn)的文本序列化创建一个字符串,并将其用作存储回调的键.这个键看起来像'mouseoverfunction changeText() {...code...}'.

但依赖函数序列化是一个糟糕的主意.ECMAScript未对该格式进行标准化("返回函数的依赖于实现的表示."); 有许多浏览器怪癖 ; 并且最重要的是,两个不同的函数可以轻松地为浏览器的当前序列化方法返回相同的字符串:

var f1= function() {};
var f2= function() {};
Run Code Online (Sandbox Code Playgroud)

f1并且f2将具有相同的字符串序列化,但它们不是同一个对象.如果您在IE上执行了addEventfor f1,然后再执行另一个for f2,则第二个属性将使用相同的序列化字符串并覆盖第一个属性.然后调用removeEvent用于f1将检索的功能f2,尝试detachEvent并失败,因为它是不一样的功能.这个例子可能看起来很人为,但是当你使用通用闭包时,它实际上非常容易做到,因为现代JavaScript现在越来越多.出于这个原因,我建议在所有情况下都避免使用ResigaddEvent.

(jQuery用户:不要担心,对于它的所有问题,jQuery不会陷入使用此代码的陷阱.)

this当你的changeText函数被IE调用时,这个hack是保存值的,它attachEvent没有设置this.但是你甚至没有使用这个this值,所以你可以使用一个更简单的版本,例如创建它来替换它的原始addEvent.

至少这个 addEvent 的缺点是众所周知的,当你在IE上测试时会立即出现this,而不是只在特定的情况下出错,当它影响到你时,可能会非常混乱并且难以调试.

再说一遍,你目前还没有为同一个事件使用多个监听器,所以你可以轻松地使用老式的DOM Level 0事件处理程序,例如:

window.onload= function() {
    var changed= false;
    document.getElementById('contactButton').onmouseover= function() {
        if (!changed) {
            alert('changing text');
        }
        changed= true;
    };
};
Run Code Online (Sandbox Code Playgroud)