不使用JavaScript中DOM事件自定义事件模型(Custom Events Model wit

2019-08-17 10:19发布

我一般是新的JavaScript和编程,以及我对物体和事件的一些问题。

说我有一个对象:

var computer = {
    keyboard: {}
}

我正在寻找的是登记事件键盘对象的方式:

computer.keyboard.registerEvent( "keyEscape" );

火灾的事件:

computer.keyboard.dispatchEvent( "keyEscape" );

和创建事件处理程序:

computer.keyboard.addEventListener( "keyEscape", function() {...} );

我知道如何与DOM元素,但不是对象做到这一点。 这是不是可以用JavaScript来实现(可能使用jQuery的帮助下)?

甚至指导半点将不胜感激。

Answer 1:

如果你想建立一个完全独立的事件系统不依赖于DOM事件,你可以有这样的事情用反应器模式

function Event(name){
  this.name = name;
  this.callbacks = [];
}
Event.prototype.registerCallback = function(callback){
  this.callbacks.push(callback);
}

function Reactor(){
  this.events = {};
}

Reactor.prototype.registerEvent = function(eventName){
  var event = new Event(eventName);
  this.events[eventName] = event;
};

Reactor.prototype.dispatchEvent = function(eventName, eventArgs){
  this.events[eventName].callbacks.forEach(function(callback){
    callback(eventArgs);
  });
};

Reactor.prototype.addEventListener = function(eventName, callback){
  this.events[eventName].registerCallback(callback);
};

使用它像DOM事件模型

var reactor = new Reactor();

reactor.registerEvent('big bang');

reactor.addEventListener('big bang', function(){
  console.log('This is big bang listener yo!');
});

reactor.addEventListener('big bang', function(){
  console.log('This is another big bang listener yo!');
});

reactor.dispatchEvent('big bang');

住在JSBin



Answer 2:

如果你不希望实现自己的事件处理机制,你可能会喜欢我的做法。 你会得到所有你知道,从通常的DOM事件的特征(preventDefault()方法为例),我认为它更轻便,因为它使用了已经实现的DOM事件处理浏览器的功能。

只要创建你的对象的构造正常的DOM事件目标对象,并通过所有的EventTarget接口调用到DOM事件目标对象:

var MyEventTarget = function(options) {
    // Create a DOM EventTarget object
    var target = document.createTextNode(null);

    // Pass EventTarget interface calls to DOM EventTarget object
    this.addEventListener = target.addEventListener.bind(target);
    this.removeEventListener = target.removeEventListener.bind(target);
    this.dispatchEvent = target.dispatchEvent.bind(target);

    // Room your your constructor code 
}

// Create an instance of your event target
myTarget = new MyEventTarget();
// Add an event listener to your event target
myTarget.addEventListener("myevent", function(){alert("hello")});
// Dispatch an event from your event target
var evt = new Event('myevent');
myTarget.dispatchEvent(evt);

还有一个的jsfiddle片段与浏览器进行测试。



Answer 3:

Necroposting一点点在这里,但我只是写这样的事情,昨晚 - 超级简单,并根据关Backbone.js的活动模块:

EventDispatcher = {

    events: {},

    on: function(event, callback) {
        var handlers = this.events[event] || [];
        handlers.push(callback);
        this.events[event] = handlers;
    },

    trigger: function(event, data) {
        var handlers = this.events[event];

        if (!handlers || handlers.length < 1)
            return;

        [].forEach.call(handlers, function(handler){
            handler(data);
        });
    }
};

这种方法是非常简单的,可扩展,使您可以在它上面建立一个更复杂的事件系统,如果你需要。

使用EventDispatcher是简单的:

function initializeListeners() {
    EventDispatcher.on('fire', fire); // fire.bind(this) -- if necessary
}

function fire(x) {
    console.log(x);
}

function thingHappened(thing) {
    EventDispatcher.trigger('fire', thing);
}

随着一些简单的命名空间,你就可以通过模块之间的基本活动自如!



Answer 4:

您可以使用JQuery做到这一点。

对于订阅您的自定义事件:

$(computer.keyboard).on('keyEscape', function(e){
    //Handler code
});

投掷您的自定义事件:

$(computer.keyboard).trigger('keyEscape', {keyCode:'Blah blah'});

可能是没有做到这一点的最好办法,但你也可以创建你的方法(的addEventListener,则dispatchEvent,...)函数将包装JQuery的逻辑,同时支持本地查找API和JQuery。



Answer 5:

最有可能的,你需要一个事件机制几种通信对象之间的媒介。

下面有你如何能做到这一点:

 /** * EventfulObject constructor/base. * @type EventfulObject_L7.EventfulObjectConstructor|Function */ var EventfulObject = function() { /** * Map from event name to a list of subscribers. * @type Object */ var event = {}; /** * List of all instances of the EventfulObject type. * @type Array */ var instances = []; /** * @returns {EventfulObject_L1.EventfulObjectConstructor} An `EventfulObject`. */ var EventfulObjectConstructor = function() { instances.push(this); }; EventfulObjectConstructor.prototype = { /** * Broadcasts an event of the given name. * All instances that wish to receive a broadcast must implement the `receiveBroadcast` method, the event that is being broadcast will be passed to the implementation. * @param {String} name Event name. * @returns {undefined} */ broadcast: function(name) { instances.forEach(function(instance) { (instance.hasOwnProperty("receiveBroadcast") && typeof instance["receiveBroadcast"] === "function") && instance["receiveBroadcast"](name); }); }, /** * Emits an event of the given name only to instances that are subscribed to it. * @param {String} name Event name. * @returns {undefined} */ emit: function(name) { event.hasOwnProperty(name) && event[name].forEach(function(subscription) { subscription.process.call(subscription.context); }); }, /** * Registers the given action as a listener to the named event. * This method will first create an event identified by the given name if one does not exist already. * @param {String} name Event name. * @param {Function} action Listener. * @returns {Function} A deregistration function for this listener. */ on: function(name, action) { event.hasOwnProperty(name) || (event[name] = []); event[name].push({ context: this, process: action }); var subscriptionIndex = event[name].length - 1; return function() { event[name].splice(subscriptionIndex, 1); }; } }; return EventfulObjectConstructor; }(); var Model = function(id) { EventfulObject.call(this); this.id = id; this.receiveBroadcast = function(name) { console.log("I smell another " + name + "; and I'm model " + this.id); }; }; Model.prototype = Object.create(EventfulObject.prototype); Model.prototype.constructor = Model; // ---------- TEST AND USAGE (hopefully it's clear enough...) // ---------- note: I'm not testing event deregistration. var ob1 = new EventfulObject(); ob1.on("crap", function() { console.log("Speaking about craps on a broadcast? - Count me out!"); }); var model1 = new Model(1); var model2 = new Model(2); model2.on("bust", function() { console.log("I'm model2 and I'm busting!"); }); var ob2 = new EventfulObject(); ob2.on("bust", function() { console.log("I'm ob2 - busted!!!"); }); ob2.receiveBroadcast = function() { console.log("If it zips, I'll catch it. - That's me ob2."); }; console.log("start:BROADCAST\n---------------"); model1.broadcast("crap"); console.log("end :BROADCAST\n---------------\n-\n-\n"); console.log("start:EMIT\n---------------"); ob1.emit("bust"); console.log("end:EMIT\n---------------"); 
 <h1>...THE SHOW IS ON YOUR CONSOLE!</h1> 



Answer 6:

下面是一个简单的扩展的穆赫辛的回答 ,表现为明显的短例子。

他都可以响应功能封装成一个React()附加功能removeEventListener()和全实例中,呈现为一个HTML文件(或看到它的jsfiddle )。

<!DOCTYPE html>
<html>

<head>
    <meta charset=utf-8 />
    <title>JS Bin</title>
    <!--https://jsfiddle.net/romleon/qs26o3p8/-->
</head>

<body>
    <script>
        function Reactor() {
            function Event(name) {
                this.name = name;
                this.callbacks = [];
            }
            Event.prototype.registerCallback = function(callback) {
                this.callbacks.push(callback);
            };
            Event.prototype.unregisterCallback = function(callback) {
                var array = this.callbacks,
                    index = array.indexOf(callback);
                if (index > -1)
                    array.splice(index, 1);
            }
            this.events = {};

            this.registerEvent = function(eventName) {
                var event = new Event(eventName);
                this.events[eventName] = event;
            };
            this.dispatchEvent = function(eventName, eventArgs) {
                var events = this.events
                if (events[eventName]) {
                    events[eventName].callbacks.forEach(function(callback) {
                        callback(eventArgs);
                    });
                }
                else
                    console.error("WARNING: can't dispatch " + '"' + eventName + '"')
            };
            this.addEventListener = function(eventName, callback) {
                this.events[eventName].registerCallback(callback);
            };

            this.removeEventListener = function(eventName, callback) {
                var events = this.events
                if (events[eventName]) {
                    events[eventName].unregisterCallback(callback);
                    delete events[eventName];
                }
                else
                    console.error("ERROR: can't delete " + '"' + eventName + '"')
            };
        }
/*
    demo of creating
*/
        var reactor = new Reactor();

        reactor.registerEvent('big bang');
        reactor.registerEvent('second bang');

/*
    demo of using
*/
        log("-- add 2 event's listeners for 'big bang' and 1 for 'second bang'")
        var callback1 = function() {
            log('This is big bang listener')
        }
        reactor.addEventListener('big bang', callback1);

        reactor.addEventListener('big bang', function() {
            log('This is another big bang listener')
        });

        reactor.addEventListener('second bang', function() {
            log('This is second bang!')
        });

        log("-- dipatch 'big bang' and 'second bang'")
        reactor.dispatchEvent('big bang');
        reactor.dispatchEvent('second bang');

        log("-- remove first listener (with callback1)")
        reactor.removeEventListener('big bang', callback1);

        log("-- dipatch 'big bang' and 'second bang' again")
        reactor.dispatchEvent('big bang');
        reactor.dispatchEvent('second bang');

        function log(txt) {
            document.body.innerHTML += txt + '<br/>'
            console.log(txt)
        }
    </script>
</body>

</html>


文章来源: Custom Events Model without using DOM events in JavaScript