不使用库在IE中创建自定义事件

22

我被指派在文档中触发自定义事件,但不能使用任何类库,如jQuery或prototype。

所以在Firefox上我可以这样做:

function fireCustomEvent(eventData)
{
    if (document.createEvent)   // Firefox
    {
        var event = document.createEvent('HTMLEvents');    // create event
        event.initEvent('myCustomEvent', true, true );     // name event
        event.data = eventData;                            // put my stuff on it
        document.dispatchEvent(event);                     // fire event
    }
    else if (document.createEventObject)    // IE
    {
        xxxxxxxxxxx
    }
}

现在我可以像这样触发它:

fireCustomEvent({
    category: 'test',
    value: 123
});

然后像这样捕获它(我可以使用jQuery):

$(document).bind('myCustomEvent', function (event) {
    doStuff(event);
});

我的问题是,我该如何使这在IE上工作(换句话说,在哪里放置xxxxxxxxxxx)?

我认为在IE中等价的代码应该是这样的:

 var event = document.createEventObject();
 event.data = eventData;
 document.fireEvent('myCustomEvent', event);

但是那样是不起作用的。IE只允许我使用预定义的事件名称(例如onclick)而且其中一些甚至不起作用(例如onmessage)。

感谢任何帮助或建议!

3个回答

25

在没有任何框架的情况下,在Javascript中添加/删除/触发事件/自定义事件:

var htmlEvents = {// list of real events
    //<body> and <frameset> Events
    onload:1,
    onunload:1,
    //Form Events
    onblur:1,
    onchange:1,
    onfocus:1,
    onreset:1,
    onselect:1,
    onsubmit:1,
    //Image Events
    onabort:1,
    //Keyboard Events
    onkeydown:1,
    onkeypress:1,
    onkeyup:1,
    //Mouse Events
    onclick:1,
    ondblclick:1,
    onmousedown:1,
    onmousemove:1,
    onmouseout:1,
    onmouseover:1,
    onmouseup:1
}
function triggerEvent(el,eventName){
    var event;
    if (typeof window.CustomEvent === 'function') {
        event = new CustomEvent(eventName);
    } else if (document.createEvent) {
        event = document.createEvent('HTMLEvents');
        event.initEvent(eventName,true,true);
    }else if(document.createEventObject){// IE < 9
        event = document.createEventObject();
        event.eventType = eventName;
    }
    event.eventName = eventName;
    if(el.dispatchEvent){
        el.dispatchEvent(event);
    }else if(el.fireEvent && htmlEvents['on'+eventName]){// IE < 9
        el.fireEvent('on'+event.eventType,event);// can trigger only a real event (e.g. 'click')
    }else if(el[eventName]){
        el[eventName]();
    }else if(el['on'+eventName]){
        el['on'+eventName]();
    }
}
function addEvent(el,type,handler){
    if(el.addEventListener){
        el.addEventListener(type,handler,false);
    }else if(el.attachEvent && htmlEvents['on'+type]){// IE < 9
        el.attachEvent('on'+type,handler);
    }else{
        el['on'+type]=handler;
    }
}
function removeEvent(el,type,handler){
    if(el.removeEventListener){
        el.removeEventListener(type,handler,false);
    }else if(el.detachEvent && htmlEvents['on'+type]){// IE < 9
        el.detachEvent('on'+type,handler);
    }else{
        el['on'+type]=null;
    }
}

var _body = document.body;
var customEventFunction = function(){
    console.log('triggered custom event');
}
// Subscribe
addEvent(_body,'customEvent',customEventFunction);
// Trigger
triggerEvent(_body,'customEvent');

演示实例


这个答案有没有被专家们评价过,有什么优缺点? - Odys
请问您为什么要检查HTML事件? - Jimmy Kane
被低估的答案。createEvent现已过时,我建议使用以下代码作为第一个现代浏览器的测试:if (typeof window.CustomEvent === 'function') { event = new CustomEvent(eventName, {detail: detail}); } - spoutnik
@SergeyGospodarets,你应该测试window.CustomEvent的类型,因为在Android WebKit < 4.3中,window.CustomEvent存在但不是构造函数。请参见http://caniuse.com/#feat=customevent。祝好,spoutnik - spoutnik
这个回答虽然有点老,但我非常喜欢。我们能否在事件中附加额外的对象信息呢?(我知道CustomEvent支持,但不确定IE版本是否支持?) - mr1031011

11

好的,根据Dean Edwards的文章,我写了以下代码,看起来似乎可行,但有点hacky(不够优雅)。下面的示例是基于在#one内嵌套的#two元素,这样我们可以模拟事件冒泡,因为我没有找到或者说没有办法在IE中冒泡自定义事件。

function bindCustomEvent (el, eventName, eventHandler) {
    if (el.attachEvent) {
        if (!el[eventName]) {
            el[eventName] = 0;
        }
        el.attachEvent("onpropertychange", function (event) {
            if (event.propertyName == eventName) {
                eventHandler(eventHandler);
            }
        });
    }
}

bindCustomEvent(document.documentElement, "fakeEvents", function (evt) {
    alert('document');
});
bindCustomEvent(document.getElementById('one'), "fakeEvents", function (evt) {
    alert('one');
});
bindCustomEvent(document.getElementById('two'), "fakeEvents", function (evt) {
    alert('two');
});

dispatchFakeEvent = function (el, eventName, bubble) {
    bubble = !bubble ? false : true;
    if (el.nodeType === 1 && el[eventName] >= 0) {
        el[eventName]++;
    }
    if (bubble && el !== document) {
        dispatchFakeEvent(el.parentNode, eventName, bubble);
    }
};

document.getElementById('click').attachEvent('onclick', function () {
    dispatchFakeEvent(document.getElementById('two'), 'fakeEvents', true);//false = bubble
});

1
虽然我只在IE7和8中测试过,但很高兴能为您效劳。 - screenm0nkey
6
如果人们坚持使用那个东西,他们就不配得到更好的东西。 - HumanCatfood
这在许多情况下都很好,但它的一个大问题是需要一种特殊的绑定事件的方式。如果您控制绑定代码,那么这很好,但如果您正在创建一个供他人使用的控件,并希望该控件具有触发自定义事件的能力,则会出现问题。不幸的是,在IE <9中,我没有找到真正触发自定义事件的方法,因此也许这是我们能做的最好的事情,只需为控件记录非标准绑定语法即可。 :/ - Elezar
如果在document上绑定而不是documentElement上绑定,onpropertychange事件不触发的原因是什么? - Deepak

3

Prototype使用ondataavailable事件在IE中触发自定义事件。


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