2011-06-03 130 views
5

在Java,C#,Actionscript等事件是用于类,而在Javascript中它似乎受限于DOM。我在这里读取一个与jquery做的样本 http://www.west-wind.com/weblog/posts/2010/May/27/NonDom-Element-Event-Binding-with-jQuery如何将JavaScriptEventListener添加到非DOM元素中?

但如果我不需要jquery,如果我想了解机制,你会怎么做?

+0

你想要做什么?一个经典的'Observer'实现呢? – 2011-06-03 16:52:40

+0

你可能想要一个[EventEmitter](https://github.com/Wolfy87/EventEmitter)。 – Thai 2011-06-03 17:13:05

+0

@Thai非常感谢! – user310291 2011-06-03 19:38:42

回答

1

在它的最简单的机制是这样的:

function PubSub() { 
    this.subs = {}; 
    this.subscribe = function(channel, sub) { 
     this.subs[channel] = this.subs[channel] || []; //create array for channel 
     this.subs[channel].push(sub); 
    }; 
    this.publish = function(channel) { 
     var args = [].slice.call(arguments, 1); //pop off channel argument 
     this.subs[channel].forEach(function(sub) { 
      sub.apply(void 0, args); //call each method listening on the channel 
     }); 
    }; 
} 

演示在这里:http://jsfiddle.net/3PNtR/

3

至少有两种方法来实现这一目标:

- 如果你是一个jQuery用户(目前,我没有),你可以用JQuery包装你的简单JavaScript对象,然后像DOM元素一样,它可以监听事件。此方法已具有answerhere。我不确定这种方法是如何工作的,我打算稍后调查,你可以自己调查。

- 通过使用VanillaJS,您可以通过创建一个事件“类”来实现相同的效果,所有愿意交互的对象都将从其中派生/创建。然后,该类的所有实例将能够注册,发射并广播一个事件。借用DOM API和AngularJS的语义,我写了一个例子,演示了如何完成这项工作以及如何使用它。那就是:

/** 
 
* 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 CODE IS IN the JavaScript pane!</h1> 
 
<h3>AND... THE SHOW IS ON YOUR CONSOLE!</h3>

您可以使用它作为一个更强大的解决方案的魅力。

相关问题