IE中的事件处理

时间:2010-07-06 10:45:08

标签: javascript javascript-events event-handling

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

它在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>

更新:我刚刚在最新的Chrome,Opera和FF中测试过没有任何问题,但是当鼠标悬停时,Safari没有做任何事情,并且IE正在抛出错误onload。

2 个答案:

答案 0 :(得分:6)

event = addEvent(

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

if (typeof obj.addEventListener != undefined)

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

obj.detachEvent("on" + type, obj[type + fn]);

由于您没有在type函数中编写名为fnaddEvent的属性,因此无法检索任何内容。

正如Crescent所说,看起来你正在使用Resig的removeEvent函数,与不匹配的addEvent配对。如果您使用他的removeEvent,则需要使用他的addEvent来使用它。

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

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

var f1= function() {};
var f2= function() {};

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

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

当IE changeText未设置attachEvent this功能时,此hack会保留this值。但是你甚至不使用this值,所以你可以使用一个更简单的版本,例如创建它来替换的original addEvent

至少 addEvent的缺点是众所周知的,并且当你使用window.onload= function() { var changed= false; document.getElementById('contactButton').onmouseover= function() { if (!changed) { alert('changing text'); } changed= true; }; }; 在IE上测试时立即出现,而不是在特定情况下出错,当它出现时影响你,可能会非常混乱,难以调试。

然后,您目前还没有为同一事件使用多个侦听器,因此您可以轻松地使用老式的DOM Level 0事件处理程序,例如:

{{1}}

答案 1 :(得分:1)

如果您需要灵活的解决方案,请转到 Dean's addEvent

// written by Dean Edwards, 2005
// with input from Tino Zijdel, Matthias Miller, Diego Perini
// http://dean.edwards.name/weblog/2005/10/add-event/

function addEvent(element, type, handler) {
    if (element.addEventListener) {
        element.addEventListener(type, handler, false);
    } else {
        // assign each event handler a unique ID
        if (!handler.$$guid) handler.$$guid = addEvent.guid++;
        // create a hash table of event types for the element
        if (!element.events) element.events = {};
        // create a hash table of event handlers for each element/event pair
        var handlers = element.events[type];
        if (!handlers) {
            handlers = element.events[type] = {};
            // store the existing event handler (if there is one)
            if (element["on" + type]) {
                handlers[0] = element["on" + type];
            }
        }
        // store the event handler in the hash table
        handlers[handler.$$guid] = handler;
        // assign a global event handler to do all the work
        element["on" + type] = handleEvent;
    }
};
// a counter used to create unique IDs
addEvent.guid = 1;

function removeEvent(element, type, handler) {
    if (element.removeEventListener) {
        element.removeEventListener(type, handler, false);
    } else {
        // delete the event handler from the hash table
        if (element.events && element.events[type]) {
            delete element.events[type][handler.$$guid];
        }
    }
};

function handleEvent(event) {
    var returnValue = true;
    // grab the event object (IE uses a global event object)
    event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
    // get a reference to the hash table of event handlers
    var handlers = this.events[event.type];
    // execute each event handler
    for (var i in handlers) {
        this.$$handleEvent = handlers[i];
        if (this.$$handleEvent(event) === false) {
            returnValue = false;
        }
    }
    return returnValue;
};

function fixEvent(event) {
    // add W3C standard event methods
    event.preventDefault = fixEvent.preventDefault;
    event.stopPropagation = fixEvent.stopPropagation;
    return event;
};
fixEvent.preventDefault = function() {
    this.returnValue = false;
};
fixEvent.stopPropagation = function() {
    this.cancelBubble = true;
};