Jquery观察者模式

我一直在互联网上查看在jquery中实现观察者模式的例子。

我想这样

observer1.observe(subject); observer2.observe(subject); 

为观察者定义一些自定义事件回调

 observer1.bind('customEvent', function(contextData) { //Some code }); observer1.bind('anotherCustomEvent', function(contextData) { //Some code }); observer2.bind('customEvent', function(contextData) { //Some code }); 

然后,以下行将触发两个观察者的customEvent回调

 subject.trigger('customEvent', contextData); 

而以下只会在observer1上触发anotherCustomEvent,因为observer2没有绑定的自定义事件

 subject.trigger('anotherCustomEvent', contextData); 

互联网上的指南更为通用:

 $( document ).on( "topicName" , function () { //..perform some behaviour }); $( document ).trigger( "topicName" ); 

(来自http://addyosmani.com/resources/essentialjsdesignpatterns/book/#observerpatternjquery的例子)我看不出上面的代码如何用来完成我正在寻找的东西。

要么我必须这样做(如果我保持它像上面的例子):

 $(document).on("customEvent", function () { observer1.trigger("customEvent"); observer2.trigger("customEvent"); }); $(subject).click(function() { $(document).trigger("customEvent"); }); 

或者更好一点:

 $(subject).click(function() { observer1.trigger("customEvent"); observer2.trigger("customEvent"); }); 

无论哪种方式,我都不得不编辑subject-click-callback或document-customEvent-callback而不是告诉观察者订阅主题。

我是否误解了观察者模式或有没有办法实现我正在寻找的东西?

http://addyosmani.com/resources/essentialjsdesignpatterns/book/#observerpatternjavascript在该章中提到了发布/订阅模式。 这对我来说可能是一种方式,但我错过了示例背后的代码。

从你的评论:

当你必须告诉主题哪些元素被选择器触发而不是具有观察者可以注册到的列表的主题时,我只是看不出这是如何实现的。

如果我错了,请纠正我,但你似乎误解了jQuery中如何实现模式。 您没有“告诉主题触发哪些元素”,并且主题没有“观察者可以注册的列表”。 它的工作原理如下:

  • 主题/发布者发出/触发某些事件(在您定义的某些情况下)。
  • 观察者/订阅者监听某些事件。 它保留了它订阅的事件列表。
  • 这都是基于DOM事件的,所以它受DOM事件模型的限制。

例如,请考虑以下HTML:

 
div 1
div 2

让内部div触发一个名为'custom'的自定义事件。 您可以定义何时应该发生这种情况,在此示例中,单击它们时会发生这种情况:

 $('div').on('click', function(e) { $(this).trigger('custom'); }); 

现在让我们让document元素订阅该自定义事件:

 $(document).on('custom', function(e) { console.log('document is handling custom event triggered by ' + e.target.id); }); 

当其中一个div触发自定义事件时,将通知观察者/订阅者并将消息记录到控制台。

该示例使用document作为观察者,原因是:事件冒泡DOM树,并且只能被触发它的祖先元素捕获。 由于document是DOM树的根,因此可以查看所有事件。 如果#div1是我们的观察者,它只会看到#div1本身触发的事件,而不会看到#div2触发的事件。

也许这种局限让你感到困惑?


有办法规避这种限制,但通常情况下,如果你想根据#div2触发的事件对#div1做一些事情,你只需从你在document元素上设置的回调(或最接近的共同祖先)来做两个div)。 无论如何,似乎你真的想要一个替代品,所以这里有一个jQuery插件的forms:

 $.fn.observe = function(eventName, callback) { return this.each(function(){ var el = this; $(document).on(eventName, function(){ callback.apply(el, arguments); }) }); } 

你可以像这样使用它:

 $('#div1').observe('custom', function(e) { // do something }); 

实例: http : //jsfiddle.net/JwJsP/1

可能不是你想要的,但观察者可以订阅听取事件:

  $(document).on('customEvent', '.iObserver', function() { console.log('i am observer'); }); // add observer $('ul li#Observer').addClass('iObserver'); //remove observer $('ul li#Observer').removeClass('iObserver'); 

如果您仍在使用jQuery的事件引擎寻找一些实现,您可以尝试以下代码:

 //The implementation (function($) { var o = $({}); $.each({ trigger: 'publish', on: 'subscribe', off: 'unsubscribe' }, function(key, val) { jQuery[val] = function() { o[key].apply(o, arguments); }; }); })(jQuery); // The way to use it is this: var somedata = [1, 2, 3, 5, 4, 7, 8]; $.publish('myEvent', somedata); // with data $.publish('myEvent'); // without data $.subscribe('myEvent', function(event, data) { // handle the event });