【问题标题】:Passing data from one Backbone view to another将数据从一个 Backbone 视图传递到另一个
【发布时间】:2013-11-25 23:34:33
【问题描述】:

假设我有以下 Backbone 视图,它加载两个链接,一个带有锚文本“test1”,另一个带有锚文本“test2”。

我绑定了一个点击事件,我得到了被点击链接的 HTML 并将其存储在 clickedHtml 变量中。

现在,这个视图由 Backbone 路由器加载。

当用户单击两个链接(test1 或 test2)中的任何一个时,路由器将加载另一个名为“main”的视图。

现在,如何将“clickedHtml”变量传递给该视图?

我应该使用 LocalStorage 吗?

我应该像 window.clickedHtml 一样全局声明它吗?

有没有更好的办法?

泰!

// file: views/test.js
            define([
                'jquery', 
                'underscore', 
                'backbone'
            ], function($, _, Backbone) {

                var Test = Backbone.View.extend({

                    el : '.test',

                    initialize : function () {

                        var that = this;

                        that.$el.html('<a href="#/main">test1</a><br /><a href="#/main">test2</a>');


                    },

                    events : {

                        'click .test a' : 'click'

                    },

                    click : function (e) {

                        var clickedHtml = $(e.target).html();

                    }

                return Test;

            });

这是我的路由器:

// file: router.js

    define([
        'jquery', 
        'underscore', 
        'backbone',
        'views/test',
        'views/main'
    ], function ($, _, Backbone, Test, Main) {

        var Router = Backbone.Router.extend({

            routes: {
                '' : 'home',
                'test' : 'test'
            }
        });

        var initialize = function () {

            var router = new Router();

            router.on('route:home', function () {

                var main = new Main();

            });

            router.on('route:test', function () {

                var test = new Test();
            });

            Backbone.history.start();
        }

        return { 

            initialize : initialize 
        }
    });

【问题讨论】:

  • 您可以将两个视图都放在一个视图中。然后你就可以访问主视图中两个子视图的所有变量了。

标签: javascript jquery backbone.js


【解决方案1】:

基本上你应该使用 Backbone.Event:(或者它在 Marionette 中的等价物)

//Declaration
var notificationService = {};
_.extend(notificationService, Backbone.Events);

//Used by listener
notificationService.on("alert", function(o) {
   alert(o);
});

//Used by publisher 
notificationService.trigger("alert", {foo:"bar"});

真正的问题是它如何从一个视图传递到另一个视图?

在我看来,你有两个选择:

  1. 在初始化中从一个视图到另一个视图的气泡 notificationService
  2. 使用返回它的 requirejs 模型包装 notificationService(创建一个可以由 requirejs 传递的“几乎全局”的 notificationService)。

虽然我有点不喜欢单例,但是在每个模型中都可以很容易地被 requirejs 注入的单例 notificationService 对象的这种情况会派上用场。

编辑

另一种选择,又快又脏,只需使用 jquery 触发 DOM 上的事件(特别是 body 元素)并在另一个视图中监听 body

 //on Listening view, after DOM is ready
$( "body" ).on( "alert", function( event, param1, param2 ) {
  alert( param1 + "\n" + param2 );
});

 //on Triggering view, after DOM is ready
$( "body").trigger( "alert", [ "Custom", "Event" ] );

注意

请注意,一旦关闭监听视图,它必须将自己从监听事件中移除(取消绑定/关闭),因此您不会有内存泄漏

【讨论】:

  • 这是我一直在使用的方法。请参阅stackoverflow.com/questions/20181679/…,但是是的,由于您使用的是 requirejs,因此您必须将其包装并至少在您的所有视图中都可用。
  • 如果您将 notificationService 设为全局,您可以在视图中使用 .listenTo 订阅来自该对象的事件(类似于我在下面发布的答案)。
【解决方案2】:

从架构上讲,您的目标应该是保持代码的通用性和可重用性。

在这种情况下,您不想做的主要事情之一是将直接引用从一个对象传递到另一个对象 - 如果您最终更改了其中一个对象的设置,或者您需要传递数据同样来自另一个对象,这会很快变得混乱。

在这种情况下广泛使用的一种设计模式是中介。也称为“发布/订阅”,您可以拥有一个集中的独立对象,用于协调对象之间的信息。某些对象将发布信息,而其他对象可以订阅它们。中介充当中介,因此对象不必直接相互通信。这使得解决方案更加通用、可重用和可维护。

更多信息在这里:

http://addyosmani.com/largescalejavascript/#mediatorpattern,

Javascript Patterns

在 Backbone 方面...如果您使用过 Marionette,您可能会遇到一个名为 wreqr 的免费迷你库(也由 Derick Bailey 实现)。您可以使用它在 Backbone 应用程序中创建一个开销较低的简单中介。

https://github.com/marionettejs/backbone.wreqr

它基本上允许您跨对象使用主干样式事件。示例如下:

首先,您需要创建一个全局可访问的中介对象,或者将其添加到您的应用命名空间或使用 require.js:

var mediator = new Wreqr.EventAggregator();

内部视图 #1

events : {
    'click .test a' : 'click'
},

click : function (e) {
     var clickedHtml = $(e.target).html();

     // trigger an 'element:click' event, which can be listened to from other
     // places in your application. pass var clickedHtml with the event
     // (passed to the arguments in your eventhandler function).
     mediator.trigger('element:click', clickedHtml); 
}

内部视图 #2

initialize: function(){
    //...
    this.listenTo(mediator, 'element:click', this.myEventHandler, this);
}

myEventHandler: function(elem){
    // elem = clickedHtml, passed through the event aggregator
    // do something with elem...
}

【讨论】:

  • 非常有帮助!谢谢你。我只需要更改为 new Backbone.Wreqr.EventAggregator() 即可使其正常工作。
【解决方案3】:

主干事件是这里的方法。 当您在视图中捕获事件时,我会使用:

click : function (e) {
    var clickedHtml = $(e.target).html();
    Backbone.Events.trigger("eventname",clickedHtml); 
}

然后,您应该能够在路由器初始化函数中捕获它,使用:

Backbone.Events.on("eventname", responseFunction); // listen out for this event 

然后在路由器中声明一个单独的函数:

responseFunction : function(clickedHtml) 
   {
       //Do whatever you want here
   }

我是凭记忆写的,所以希望它有意义。我也没有测试过在路由器中捕获这样的事件,但它应该工作。

HTH。

【讨论】:

    【解决方案4】:

    在您概述的确切情况下,我将在您的全局命名空间上创建一个临时存储对象并使用它在您的视图之间传输数据,它有点“hacky”但它比使用本地存储或直接使用窗口对象更好,至少在您自己的全局命名空间中有一个临时对象,对象使用的意图是已知的。

    我发现将http://backbonejs.org/#Events 用于在两个视图之间传递数据的类似目的会更好,尽管它确实取决于您如何构建页面,如果页面上有两个视图表示“控件”或“组件”这种方法非常有效。

    如果您发布指向您网站的链接或其他内容,我可以查看并为您提供更多帮助。

    罗斯

    【讨论】:

      【解决方案5】:

      您也许可以将其作为属性存储在视图中:

      click : function (e) {
           this.clickedHtml = $(e.target).html();
      }
      

      如果您的路由器可以访问这两个视图,那么它可以简单地将firstView.clickedHtml 属性传递给secondView 中的函数(或传递给初始化程序)

      【讨论】:

      • Ty,我已经添加了我的路由器,不知道如何从路由器文件中访问该属性。
      • 您通过视图访问该属性。为此,您需要公开您的视图。
      猜你喜欢
      • 2015-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多