【问题标题】:Event Handling in IEIE 中的事件处理
【发布时间】:2010-07-06 10:45:08
【问题描述】:

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

它在 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 抛出上述错误时,Safari 什么也没做。

【问题讨论】:

  • 呸。你从哪里得到removeEvent?看起来类似于 John Resig 的实现 (ejohn.org/blog/flexible-javascript-events),但与 addEvent 不对称。
  • 也许我只是一个简单的人,但如果这是我的页面,我会使用一个简单的标志变量来处理一次性事件处理程序,我会在第一次调用后翻转它。如果我真的想要进行大量的事件处理,我会让一些经过良好测试的框架来处理丑陋的细节。
  • 我差点再次抓住 jQuery,但这次想深入挖掘一下。总是想继续学习。

标签: javascript javascript-events event-handling


【解决方案1】:
event = addEvent(

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

if (typeof obj.addEventListener != undefined)

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

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

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

正如 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 上为f1 做了一个addEvent,然后为f2 做了另一个,第二个属性将使用相同的序列化字符串并覆盖第一个属性。然后为removeEvent 调用f1 将检索f2 的函数,尝试detachEvent 它并失败,因为它不是同一个函数。这个例子可能看起来很做作,但实际上当你使用泛型闭包时很容易意外发生,因为现代 JavaScript 现在越来越多。出于这个原因,我建议在任何情况下都避免使用 Resig 的 addEvent

(jQuery 用户:不用担心,jQuery 不会陷入使用这段代码的陷阱。)

当您的 changeText 函数被 IE 回调时,此 hack 可以保留 this 的值,而 IE 的 attachEvent 没有设置 this。但是您甚至不使用 this 值,因此您可以使用更简单的版本,例如创建它来替换的 original addEvent

至少 that addEvent 的缺点是众所周知的,并且当您使用 this 在 IE 上进行测试时会立即显示出来,而不是仅在影响您的特定情况下出错, 可能会非常混乱且难以调试。

再说一次,您目前甚至没有为同一个事件使用多个侦听器,因此您可以轻松摆脱老式的 DOM Level 0 事件处理程序,例如:

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

【讨论】:

  • 我认为这是关于 SO 的第一个答案,它解决了 Resig 的 addEvent 条目的问题。在这个答案的 cmets 中有一个简短的交流:stackoverflow.com/questions/1466875/ies-understanding-of-this/… kangax 启发了我依靠函数反编译/序列化来识别函数对象的失败。写得好。一个++++++++
【解决方案2】:

如果您想要灵活的解决方案,请选择 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;
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多