管理 jQuery 自定义事件

发布于 2024-09-27 04:12:37 字数 920 浏览 1 评论 0原文

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

我正在开发 .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对象来追踪谁绑定了哪些事件,并且只允许事件绑定一次。我遇到的问题是,在存储/绑定事件时,我无法跟踪谁创建了它,因此如果需要,我无法取消注册它......也许未注册的事件不是必需的事件。

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

I've done a few hours of additional research but I still can't find a good pattern to what I would think is a common problem.

I'm working on a .Net MVC2 app. Our app is made up of a main page then a number of partial views (included pages) each one of the partial views corresponds to a widget consisting of an HTML structure and JS-jQuery guts

Some of our widgets have rich interactions with each other so of course we are using the jQuery's event binding something to the effect of this:

Data Summary Widget

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

Data Manipulation Widget

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

The problem we are having is that as a user navigates to parts of the applications these widgets (HTML/DOM) are removed from the page and replace with the new set of partial views. When a user navigates back the HTML (visual representation) is reloaded along with the jQuery binding which creates a double binding.

So far my solutions seem lame to me.

(1) bind to the DOM object the binding is for:

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

The problem with this is that then my triggering widget needs to know what DOM bject to trigger on: $("#summaryobject") which kind of defeats the purpose.

(2) Create a EventBus object to tract who bound which events and only allow events to be bound once. The problem I am having is when storing/binding the events I can't track who created it so I can't unregister it if I need to....perhaps unregistered events isn't event necessary.

What patterns are others using to manage custom events?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

南汐寒笙箫 2024-10-04 04:12:37

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

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

  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`

There are two good solutions to your problem (that I can see).

  1. Remove all of your bind calls and replace them with a single call to delegate or live and set up a listener which listens for all of events that occur in your application and routes them to the appropriate places. (In other words, create a Controller).

  2. Use an EventBus that allows events to be unsubscribed as well as subscribed. The simplest way I've seen to do this with a EventBus is Peter Michaux's 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;
};

An example of using this second method would be:

EventManager.subscribe("DataUpdated", summaryobject, "updateTotals");
// ... at some point later on ...
EventManager.fire("DataUpdated");
// Fires `updateTotals` with `this` bound to `summaryobject`
失退 2024-10-04 04:12:37

您可以尝试一些方法,例如:

  1. 为事件类型命名。
    这样一来,虽然不
    在两者之间创建绑定
    具体视图实例,您可以
    创建广义关系
    不同类型的视图之间。来自你的
    上面的例子:

    数据摘要小部件 A

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

    数据操作小部件 A

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

    查看此处的文档:
    http://api.jquery.com/bind/

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

You could try a couple of things, like:

  1. Namespacing your event types.
    This way, while not
    creating a binding between two
    specific view instances, you can
    create a generalized relationship
    between types of views. From your
    example above:

    Data Summary Widget A

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

    Data Manipulation Widget A

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

    Check out the documentation in here:
    http://api.jquery.com/bind/

  2. Unloading the event handlers
    whenever a widget or group of them
    is unloaded, prior to loading the
    new DOM / handlers.

扛起拖把扫天下 2024-10-04 04:12:37

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

Have you tried using live() binding method ?

慈悲佛祖 2024-10-04 04:12:37

我现在最终这样做了:

在我的 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 对象。然而,我们的对象每次加载时都会被覆盖,所以最糟糕的情况是应用程序中的每个对象都可以注册一次,即使它们没有被使用。

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

I ended up doing this for now:

under my pagemanager object I wrote this method

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

For my widgets class I did this.

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

For any instance of a widget you call registerForEvent to bind events.

This is far from a perfect solution. Our design will still have memory leaks in that we don't unregister our JS objects. However, our objects are overwritten each time they are loaded so worse case is that every object in the application can be registered once, even if they are not used.

However, binding a method to an event binds to the document object which is not overwritten or course. So this code will stop us from rebinding. We still have a bit of a sloppy setup however it's ramifications should be minimized.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文