关于非DOM元素的事件监听器
我正在尝试实现一个小的MVC框架,现在我正在实现视图模型绑定器,我的意思是,当模型更改时,触发刷新/渲染/模型上的任何内容。 所以,我需要一个对象的事件监听器:
model.on("customEvent",appendItem); $("#button").on("click",function(){ model.add(item); model.trigger("customEvent"); }); function appendItem(item) { $("#content").append(item.toHTML()); }
那么如何在对象上创建事件监听器呢?
如果您已经在使用jQuery,则可以使用其内置的事件处理工具。
这是一个鲜为人知的事实,您也可以将任何类型的Javascript对象放入jQuery集合中,而不仅仅是DOM元素。 然后,您可以在这些对象上使用一组有限的jQuery方法( .data()
.prop()
.on()
.trigger()
.triggerHandler()
.trigger()
和.triggerHandler()
)。
//create the model - it can be any kind of object var model = {}; //pass it to the jQuery function and you have a jQuery collection //you can put an event handler on the object $(model).on('customEvent', function () { console.log('hehe'); }); //and trigger it $(model).trigger('customEvent');
- 阅读手册中的更多内容
- 试试演示
对于那些不使用jQuery并且有兴趣为自己的stuf布线的人,以下是您可以实现类似目标的方法:
/** * 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---------------");
THE CODE IS IN THE JavaScript SECTION!
AND... THE SHOW IS ON YOUR CONSOLE!