在JavaScript中不使用DOM事件的自定义事件模型

在JavaScript中不使用DOM事件的自定义事件模型,javascript,events,object,handler,Javascript,Events,Object,Handler,一般来说,我对JavaScript和编程是新手,我对对象和事件有一些疑问 假设我有一个目标: var computer = { keyboard: {} } 我正在寻找一种将事件注册到键盘对象的方法: computer.keyboard.registerEvent( "keyEscape" ); 触发事件: computer.keyboard.dispatchEvent( "keyEscape" ); 并创建事件处理程序: computer.keyboard.addEventLis

一般来说,我对JavaScript和编程是新手,我对对象和事件有一些疑问

假设我有一个目标:

var computer = {
    keyboard: {}
}
我正在寻找一种将事件注册到键盘对象的方法:

computer.keyboard.registerEvent( "keyEscape" );
触发事件:

computer.keyboard.dispatchEvent( "keyEscape" );
并创建事件处理程序:

computer.keyboard.addEventListener( "keyEscape", function() {...} );
我知道如何处理DOM元素,但不知道如何处理对象。这是可以用JavaScript实现的吗(也许可以借助JQuery)


即使是最细微的指导也会非常感激。

如果您想在不依赖DOM事件的情况下创建一个完全独立的事件系统,您可以使用reactor模式创建类似这样的系统

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');

如果您不想实现自己的事件处理机制,您可能会喜欢我的方法。您将从常见的DOM事件(例如preventDefault())中获得您所知道的所有功能,我认为它更轻量级,因为它使用了浏览器已经实现的DOM事件处理功能

只需在对象的构造函数中创建一个普通的DOM EventTarget对象,并将所有EventTarget接口调用传递给DOM EventTarget对象:

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);

还可以使用浏览器对其进行测试。

最可能的情况是,您需要一个事件机制作为多个对象之间的通信媒介

以下是如何实现这一目标:

/**
*EventfulObject构造函数/基。
*@type EventfulObject_L7.EventfulObjectConstructor|函数
*/
var EventfulObject=函数(){
/**
*从事件名称映射到订阅服务器列表。
*@type对象
*/
var事件={};
/**
*EventfulObject类型的所有实例的列表。
*@type数组
*/
var实例=[];
/**
*@返回{EventfulObject_L1.EventfulObjectConstructor}一个`EventfulObject`。
*/
var EventfulObjectConstructor=函数(){
实例。推(这个);
};
EventfulObjectConstructor.prototype={
/**
*广播给定名称的事件。
*所有希望接收广播的实例都必须实现“receiveBroadcast”方法,正在广播的事件将传递给该实现。
*@param{String}name事件名称。
*@returns{undefined}
*/
广播:功能(名称){
forEach(函数(实例){
(instance.hasOwnProperty(“receiveBroadcast”)&typeof实例[“receiveBroadcast”]=“function”)&&
实例[“接收广播”](名称);
});
},
/**
*仅向订阅了给定名称的实例发出该事件。
*@param{String}name事件名称。
*@returns{undefined}
*/
emit:函数(名称){
event.hasOwnProperty(名称)和&event[name].forEach(函数(订阅){
subscription.process.call(subscription.context);
});
},
/**
*将给定操作注册为命名事件的侦听器。
*此方法将首先创建一个由给定名称标识的事件(如果还不存在)。
*@param{String}name事件名称。
*@param{Function}操作侦听器。
*@返回{Function}此侦听器的注销函数。
*/
on:函数(名称、操作){
event.hasOwnProperty(名称)| |(事件[名称]=[]);
事件[名称]。推送({
背景:这,,
过程:行动
});
var subscriptionIndex=event[name].length-1;
返回函数(){
事件[名称]。拼接(subscriptionIndex,1);
};
}
};
返回EventfulObjectConstructor;
}();
变量模型=函数(id){
调用(this);
this.id=id;
this.receiveBroadcast=函数(名称){
log(“我闻到另一个“+name+”,我是模特“+this.id”);
};
};
Model.prototype=Object.create(EventfulObject.prototype);
Model.prototype.constructor=模型;
//------测试和使用(希望足够清楚…)
//------------注意:我没有测试事件注销。
var ob1=新的EventfulObject();
ob1.on(“垃圾”,函数(){
log(“在广播中说废话?-别把我算在内!”);
});
var模型1=新模型(1);
var模型2=新模型(2);
模型2.关于(“半身像”,函数(){
log(“我是model2,我正在崩溃!”);
});
var ob2=新的EventfulObject();
ob2.on(“半身像”,函数(){
log(“我是ob2-busted!!!”;
});
ob2.receiveBroadcast=函数(){
log(“如果它拉拉链,我会抓住它。-那是我的ob2。”);
};
console.log(“开始:广播\n----------------”;
模式1.广播(“垃圾”);
console.log(“end:BROADCAST\n--------------\n-\n”);
console.log(“开始:发射\n---------------------------”;
ob1.发射(“胸围”);
log(“end:EMIT\n----------------”

…节目在您的控制台上我在这里发布了一点,但我昨晚刚刚写了类似的东西-非常简单,基于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);
        });
    }
};

使用一些简单的名称空间,您将能够轻松地在模块之间传递基本事件

您可以使用JQuery来完成

要订阅自定义活动,请执行以下操作:

$(computer.keyboard).on('keyEscape', function(e){
    //Handler code
});
$(computer.keyboard).trigger('keyEscape', {keyCode:'Blah blah'});
用于投掷自定义事件:

$(computer.keyboard).on('keyEscape', function(e){
    //Handler code
});
$(computer.keyboard).trigger('keyEscape', {keyCode:'Blah blah'});

这可能不是最好的方法,但您也可以在方法(addEventListener、dispatchEvent等)中创建函数来包装JQuery逻辑,以支持原生api和JQuery。

这里是的一个简单扩展,作为一个清晰而简短的示例提供

他的所有React函数都封装到一个
React()
,添加了一个函数
removeEventListener()
,整个示例以一个HTML文件的形式呈现(或在上查看)


JS-Bin
功能反应器(){
函数事件(名称){
this.name=名称;
this.callbacks=[];
}
Event.prototype.registerCallback=函数(回调){
this.callbacks.push(回调);
};
Event.prototype.unregisterCallback=函数(回调)