JavaScript自定义事件监听器

50

我想知道有没有人可以帮助我理解如何创建不同的自定义事件监听器。

我没有具体的事件案例,但我想学习一般情况下如何实现它,这样我就可以在需要的地方应用它。

我想要做的事情是为了以防万一有些人需要知道:

var position = 0;

for(var i = 0; i < 10; i++)
{
    position++;
    if((position + 1) % 4 == 0)
    {
        // do some functions
    }
}

请参见这个问题 - bfavaretto
你可以使用像jQuery这样的库来创建自定义事件和监听器。请查看http://fuelyourcoding.com/jquery-custom-events-they-will-rock-your-world/和http://api.jquery.com/trigger/。 - T. Junghans
11
您发帖的代码与事件处理有什么关系?您是否希望将此代码作为响应事件运行? - Felix Kling
请查看此链接 - Nemoy
4个回答

71
var evt = document.createEvent("Event");
evt.initEvent("myEvent",true,true);

// custom param
evt.foo = "bar";

//register
document.addEventListener("myEvent",myEventHandler,false);

//invoke
document.dispatchEvent(evt);

以下是更本地化触发和监听事件的方法:http://www.kaizou.org/2010/03/generating-custom-javascript-events/


11
注意:createEvent 方法已被弃用。请改用事件构造函数 - Rahil Wazir
4
IE 不支持事件构造函数。 - Nilpo
如果你想要在 IE 上使用 CustomEvent,可以尝试使用 dom4。这是一个跨浏览器的 _polyfill_,提供了 DOM 4 Level 4 接口。使用它,你就可以在 IE 8 或以上版本上使用 CustomEvent - Tsutomu

47

实现自定义事件并不难。您可以用许多方式来实现它。最近我是这样做的:

/***************************************************************
*
*   Observable
*
***************************************************************/
var Observable;
(Observable = function() {
}).prototype = {
    listen: function(type, method, scope, context) {
        var listeners, handlers;
        if (!(listeners = this.listeners)) {
            listeners = this.listeners = {};
        }
        if (!(handlers = listeners[type])){
            handlers = listeners[type] = [];
        }
        scope = (scope ? scope : window);
        handlers.push({
            method: method,
            scope: scope,
            context: (context ? context : scope)
        });
    },
    fireEvent: function(type, data, context) {
        var listeners, handlers, i, n, handler, scope;
        if (!(listeners = this.listeners)) {
            return;
        }
        if (!(handlers = listeners[type])){
            return;
        }
        for (i = 0, n = handlers.length; i < n; i++){
            handler = handlers[i];
            if (typeof(context)!=="undefined" && context !== handler.context) continue;
            if (handler.method.call(
                handler.scope, this, type, data
            )===false) {
                return false;
            }
        }
        return true;
    }
};

Observable对象可以通过将Observable的原型与需要它的构造函数的原型混合在一起,以便由任何构造函数重复使用和应用。

要开始监听,您必须向可观察对象注册自己,如下所示:

var obs = new Observable();
obs.listen("myEvent", function(observable, eventType, data){
    //handle myEvent
});
如果您的监听器是对象的方法,例如:
obs.listen("myEvent", listener.handler, listener);

listener是一个对象的实例,该对象实现了"handler"方法。

现在,当Observable对象希望通知其监听器发生了一些事情时,它可以调用其fireEvent方法:

this.fireEvent("myEvent", data);

在这里,data是一些可能会令监听器感兴趣的数据。您可以自行决定放入其中的内容 - 您最了解自己的自定义事件由什么组成。

fireEvent方法只是遍历所有已注册“myEvent”的监听器,并调用注册的函数。如果该函数返回false,则表示该事件被取消,并且可观察对象不会调用其他监听器。因此,整个fireEvent方法也将返回false,因此可观察对象知道它正在通知其听众的任何操作现在都应该被回滚。

也许这种解决方案并不适合每个人,但我从这个相对简单的代码中获得了很多好处。


你从哪里调用 this.fireEvent("myEvent", data)?我对 "this" 的作用域感到困惑。 - perfect_element
我写道:“Observable对象现在可以调用其fireEvent方法”。因此,这是指可观察对象的实例(或混合其方法的对象)。 - Roland Bouman
上述解决方案与在文档DOM对象上创建、添加和发送自定义事件的解决方案之间是否存在行为/性能上的显着差异? - Pappa
@Pappa 我不知道。我开始这样做是为了拥有一个可以在任何地方工作的东西。createEvent 和 CustomEvent 构造函数并不被所有地方支持。 - Roland Bouman

14

6
在同一页上的 https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events#Creating_events 中提到,这在IE中不受支持。 - phpLearner

9

这里是一个非常简单的(TypeScript/Babelish)实现:

const simpleEvent = <T extends Function>(context = null) => {
    let cbs: T[] = [];
    return {
        addListener: (cb: T) => { cbs.push(cb); },
        removeListener: (cb: T) => { let i = cbs.indexOf(cb); cbs.splice(i, Math.max(i, 0)); },
        trigger: (<T> (((...args) => cbs.forEach(cb => cb.apply(context, args))) as any))
    };
};

您可以这样使用它:
let onMyEvent = simpleEvent();
let listener = (test) => { console.log("triggered", test); };
onMyEvent.addListener(listener);
onMyEvent.trigger("hello");
onMyEvent.removeListener(listener);

或者在像这样的类中

class Example {
    public onMyEvent = simpleEvent(this);
}

如果您想使用纯JavaScript,可以使用TypeScript playground进行转译。


这真是相当优雅。 - aggregate1166877

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