2

我已经做了几个小时的额外研究,但我仍然找不到一个好的模式来解决我认为是常见问题的问题。

我正在开发一个 .Net MVC2 应用程序。我们的应用程序由一个主页组成,然后是多个部分视图(包含的页面),每个部分视图对应于一个由HTML结构和JS-jQuery胆量组成的小部件

我们的一些小部件相互之间有丰富的交互,所以我们当然使用 jQuery 的事件绑定来达到以下效果:

数据摘要小部件

$(document).bind("DataUpdated", summaryobject.updateTotals());

数据操作小部件

$(document).trigger("DataUpdated");

我们遇到的问题是,当用户导航到应用程序的某些部分时,这些小部件 (HTML/DOM) 会从页面中删除并替换为新的部分视图集。当用户导航回来时,HTML(视觉表示)与创建双重绑定的 jQuery 绑定一起重新加载。

到目前为止,我的解决方案对我来说似乎很蹩脚。

(1) 绑定到绑定所针对的 DOM 对象:

$("#summaryobject").bind("DataUpdated", summaryobject.updateTotals());

这样做的问题是,然后我的触发小部件需要知道要触发的 DOM 对象:$("#summaryobject")哪种方式违背了目的。

(2) 创建一个EventBus对象来追踪谁绑定了哪些事件,并且只允许事件绑定一次。我遇到的问题是,在存储/绑定事件时,我无法跟踪谁创建了它,所以如果需要,我无法取消注册它……也许未注册的事件不是必要的事件。

其他人使用什么模式来管理自定义事件?

4

4 回答 4

1

您的问题有两个很好的解决方案(我可以看到)。

  1. 删除所有bind调用并将它们替换为对delegateor的单个调用,live并设置一个侦听器,该侦听器侦听应用程序中发生的所有事件并将它们路由到适当的位置。(换句话说,创建一个控制器)。

  2. 使用允许取消订阅和订阅事件的 EventBus。我见过的使用 EventBus 执行此操作的最简单方法是 Peter Michaux 的Eventing script


/* 
Extremely loosely coupled custom events
Source: 
http://peter.michaux.ca/articles/anonymous-events-extremely-loose-coupling
*/

EventManager = {};

EventManager.events = {};

EventManager.subscribe = function( event_name, subscriber, method_name ) {
    var event = this.events[event_name];
    if ( ! event ) {
        event = this.events[event_name] = [];
    }
    event.push( { s: subscriber, m: method_name } );
    return this;
};

EventManager.unsubscribe = function( event_name, subscriber ) {
    var event = this.events[event_name];
    if ( ! event ) {
        return;
    }
    for ( var i = event.length - 1; i >= 0; i-- ) {
        if ( event[i].s === subscriber ) {
            event.splice( i, 1 );
        }
    }
    return this;
};

EventManager.unsubscribe_all = function( event_name ) {
    delete this.events[event_name];
    return this;
};

EventManager.fire = function( event_name ) {
    var event = this.events[event_name];
    if ( ! event ) {
        return this;
    }
    for ( var i = event.length - 1; i >= 0; i-- ) {
        subscription = event[i];
        subscription.s[subscription.m].apply( subscription.s, arguments );
    }
    return this;
};

使用第二种方法的一个例子是:

EventManager.subscribe("DataUpdated", summaryobject, "updateTotals");
// ... at some point later on ...
EventManager.fire("DataUpdated");
// Fires `updateTotals` with `this` bound to `summaryobject`
于 2010-10-08T16:53:59.103 回答
0

您可以尝试几件事,例如:

  1. 命名您的事件类型。这样,虽然不会在两个特定视图实例之间创建绑定,但您可以在视图类型之间创建通用关系。从你上面的例子:

    数据摘要小部件 A

    $(document).bind("DataUpdated.Statistics", summaryobject.updateTotals());
    

    数据操作小部件 A

    $(document).trigger("DataUpdated.Statistics");
    

    在这里查看文档:http: //api.jquery.com/bind/

  2. 在加载新的 DOM / 处理程序之前,每当卸载一个小部件或一组事件处理程序时卸载事件处理程序。

于 2010-10-08T16:54:23.840 回答
0

您是否尝试过使用live()绑定方法?

于 2010-10-08T16:55:46.363 回答
0

我现在最终这样做了:

在我的 pagemanager 对象下我写了这个方法

function PageManager() {
    this.eventBusRegistry = [];

    ///<summary>Registers Event if not already bound</summary>
    this.registerForEvent = function (eventName, eventOwner, functionToBind) {
        if (this.eventBusRegistry[eventName + eventOwner] == null) {
            this.eventBusRegistry[eventName + eventOwner] = "BOUND";
            $(document).bind(eventName, functionToBind);
        }
    }
}

对于我的小部件类,我这样做了。

   ///<summary>Widget</summary>
    function Widget(inWidgetName) {

        //the data you wish to update.
        this.data = {};
        //name of widget
        this.widgetName = inWidgetName;
    }

    Widget.prototype.registerForEvent = function (eventName, functiontoBind) {
       //Session is the instance of PageManager
        Session.registerForEvent(eventName, this.widgetName, functiontoBind);
    };

对于小部件的任何实例,您调用 registerForEvent 来绑定事件。

这远非完美的解决方案。我们的设计仍然存在内存泄漏,因为我们没有取消注册我们的 JS 对象。然而,我们的对象在每次加载时都会被覆盖,所以更糟糕的情况是应用程序中的每个对象都可以注册一次,即使它们没有被使用。

但是,将方法绑定到事件会绑定到未覆盖或课程的文档对象。所以这段代码会阻止我们重新绑定。我们仍然有一些草率的设置,但它的影响应该最小化。

于 2010-10-08T21:45:02.643 回答