Javascript IE中的事件处理

Javascript IE中的事件处理,javascript,javascript-events,event-handling,Javascript,Javascript Events,Event Handling,下面包含的代码允许我在用户第一次将鼠标移到某个元素上时执行某些操作,然后删除该事件 它在W3C事件模型浏览器中运行良好,但在IE6-8中不断抛出错误。我从另一个问题得到了代码,并相信它能处理IE。有人看到我做错了什么吗 <script type="text/javascript"> function setMouseEvent() { //Tel: 01 8279 400 event = addEvent(document.getEle

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

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

函数setMouseeEvent(){
//电话:018279400
event=addEvent(document.getElementById('contactButton'),'mouseover',changeText);
}
函数changeText(){
警惕(“工作!”);
removeEvent(document.getElementById('contactButton')、'mouseover',changeText);
}
功能加法器(obj,类型,fn){
if(obj.addEventListener的类型!=未定义){
obj.addEventListener(类型,fn,false);
}
else if(obj.attachEvent的类型!=未定义){
对象附件(“on”+类型,fn);
}
}
功能移除事件(obj,类型,fn){
if(obj.addEventListener的类型!=未定义){
对象removeEventListener(类型,fn,false);
}
else if(obj.attachEvent的类型!=未定义){
obj.detachEvent(“on”+类型,obj[type+fn]);
obj[type+fn]=null;
obj[“e”+类型+fn]=空;
}
}
window.onload=setMouseEvent;
更新:我刚刚测试了最新的Chrome、Opera和FF,没有任何问题,但是当我将鼠标移到Safari上时,Safari什么也不做,IE正在将错误重新加载,如前所述。

如果您想要灵活的解决方案,请选择

// 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;
};
addEvent
不返回任何内容;您正在将
未定义的
缺少返回值分配给全局变量
事件
(因为您在函数中没有说
var事件
)。这将导致IE中出现异常,该异常使用全局
事件
作为特殊对象将事件详细信息传递给处理程序,因此不允许为其分配其他内容

if (typeof obj.addEventListener != undefined)
typeof
始终返回一个字符串,该字符串的测试值永远不会等于
未定义的
unvalue,因此IE将始终使用非IE fork并失败。您的意思是带字符串的
if(typeof obj.addEventListener!==“undefined”)

obj.detachEvent("on" + type, obj[type + fn]);
由于您没有在
addEvent
函数中编写名称为
type
fn
的属性,因此将无法检索任何内容

正如Crescent所说,看起来您正在使用Resig的
removeEvent
函数,与不匹配的另一个
addEvent
配对。如果您使用他的
removeEvent
,您将需要使用他的
addEvent
来处理它

然而,我无论如何都不会使用这些函数:它们非常狡猾。我知道这是2005年,当这个构思不周的代码“赢得”quirksmode的addEvent竞赛时,但即使在那时,我们也应该知道得更多。问题是它从事件名称和函数代码的文本序列化(
type+fn
)创建一个字符串,并将其用作存储回调的键。此键的外观类似于
'mouseoverfunction changeText(){…code…}'

但依赖函数序列化是一个糟糕的想法。ECMAScript未对格式进行标准化(“返回函数的依赖于实现的表示”);有,;同样重要的是,对于浏览器当前的序列化方法,两个不同的函数可以轻松返回相同的字符串:

var f1= function() {};
var f2= function() {};
f1
f2
将具有相同的字符串序列化,但它们不是相同的对象。如果在IE上为
f1
添加了一个
addEvent
,然后为
f2
添加了另一个,则第二个属性将使用相同的序列化字符串并覆盖第一个属性。然后为
f1
调用
removeEvent
将检索
f2
的函数,尝试
detachEvent
并失败,因为它不是同一个函数。这个例子看起来有些做作,但实际上,当您使用通用闭包时,很容易发生意外,因为现代JavaScript现在做的越来越多。因此,我建议在所有情况下都避免Resig的
addEvent

(jQuery用户:别担心,jQuery不会因为使用此代码而陷入陷阱。)

当IE调用你的
changeText
函数时,IE的
attachEvent
没有设置
This
时,这个hack可以保留
This
值。但是您甚至不使用
这个
值,因此您可以使用一个更简单的版本,比如它被创建来替换的版本

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

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

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

讨厌。你从哪里得到的
removeEvent
?看起来类似于John Resig的实现(),但与
addEvent
并不对称。也许我只是个傻瓜,但如果这是我的页面,我会用一个简单的标志变量处理一次性事件处理程序,我会在第一次调用后翻转它。如果我真的想做大量的事件争论,我会让一些经过良好测试的框架来处理难看的细节。一直想继续学习。我想这是第一个答案,可以解决Resig的
addEvent
条目的不足。在对这个答案的评论中有一个简短的交流:kangax告诉我依赖函数反编译的失败之处
window.onload= function() {
    var changed= false;
    document.getElementById('contactButton').onmouseover= function() {
        if (!changed) {
            alert('changing text');
        }
        changed= true;
    };
};