简体   繁体   English

将数据从一个Backbone视图传递到另一个

[英]Passing data from one Backbone view to another

Lets say I have the following Backbone view which loads two links, one with the anchor text "test1" and the other with the anchor text "test2". 假设我有以下Backbone视图,它加载两个链接,一个带锚文本“test1”,另一个带锚文本“test2”。

I bind a click event and I get the HTML of the link that was clicked and store it inside the clickedHtml variable. 我绑定了一个click事件,我得到了点击链接的HTML并将其存储在clickedHtml变量中。

Now, this view is loaded by a Backbone router. 现在,此视图由Backbone路由器加载。

When the user clicks either one of the two links (test1 or test2) another view called "main" will be loaded by the router. 当用户单击两个链接中的任何一个(test1或test2)时,路由器将加载另一个名为“main”的视图。

Now, how can I pass the "clickedHtml" variable to that view? 现在,我如何将“clickedHtml”变量传递给该视图?

Should I use LocalStorage? 我应该使用LocalStorage吗?

Should I declare it globally like window.clickedHtml? 我应该像window.clickedHtml一样全局声明吗?

Is there a better way? 有没有更好的办法?

Ty! 泰!

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

            });

Here is my router: 这是我的路由器:

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

Basicly you should use Backbone.Event:(Or it's equivalents in Marionette) 基本上你应该使用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"});

The real question is how does it get passed from one view to another? 真正的问题是它如何从一个视图传递到另一个视图?

The way I see it, you have 2 options: 我看到它的方式,你有两个选择:

  1. Bubble notificationService from one view to another in initialization 初始化时,bubble notificationService从一个视图到另一个视图
  2. Wrap the notificationService with a requirejs model that returns it (creates a 'almost global' notificationService that can be passed by requirejs). 使用返回它的requirejs模型包装notificationService(创建一个可以由requirejs传递的'几乎全局'的notificationService)。

Although I don't like singletons a bit, this case a of a singleton notificationService object that can easily get injected by requirejs in every model will come in handy. 虽然我不喜欢单身,但这种情况下,一个单独的notificationService对象可以很容易地被每个模型中的requirejs注入,这将派上用场。

EDIT : 编辑

Another option, the quick and dirty one , just use jquery to trigger event on the DOM (specifically the body element) and listen to body in the other view 另一个选项, 快速和脏 ,只需使用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" ] );

NOTE : 注意

notice that once a listening view is closed, it must removes itself from listening to events (unbind/off), so you wont have memory leak 请注意,一旦监听视图关闭,它必须将自己从侦听事件中取消(解除绑定/关闭),因此您不会有内存泄漏

Architecturally speaking, your aim should be to keep your code generic & reusable. 从架构上讲,您的目标应该是保持代码的通用性和可重用性。

One of the main things you don't want to do in a situation like this is to pass direct references from one object to another - if you end up changing the setup of one of the objects, or you need to pass data from another object as well, this can get messy really fast. 在这种情况下你不想做的主要事情之一是将直接引用从一个对象传递到另一个对象 - 如果你最终改变其中一个对象的设置,或者你需要从另一个对象传递数据同样,这可能会非常快。

One design pattern that's widely used in situations like this is a mediator. 在这种情况下广泛使用的一种设计模式是中介。 Also known as "pub/sub" you can have a centralized standalone object that mediates information between objects. 也称为“pub / sub”,您可以拥有一个集中的独立对象,用于在对象之间调解信息。 Certain objects will publish information and other objects can subscribe to them. 某些对象将发布信息,其他对象可以订阅它们。 The mediator acts as an intermediary so that the objects never have to communicate directly with each other. 调解器充当中介,以便对象永远不必彼此直接通信。 This makes a much more generic, reusable and maintainable solution. 这使得更通用,可重用和可维护的解决方案成为可能。

More info here: 更多信息:

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

Javascript Patterns Javascript模式

On the Backbone side of things... If you've used Marionette, you may have come across a complimentary mini-library (also implemented by Derick Bailey) called wreqr . 在Backbone方面......如果您使用过Marionette,您可能会遇到一个名为wreqr的免费迷你图书馆(也由Derick Bailey执行)。 You can use this to create a simple mediator with low-overhead in your Backbone applications. 您可以使用它在Backbone应用程序中创建一个具有低开销的简单介体。

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

It basically allows you to use backbone style events across objects. 它基本上允许您跨对象使用骨干样式事件。 Example below: 示例如下:

First, you need to create a globally accessible mediator object, or add it to your app namespace or use require.js: 首先,您需要创建一个全局可访问的中介对象,或将其添加到您的应用程序命名空间或使用require.js:

var mediator = new Wreqr.EventAggregator();

inside View #1 在视图#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); 
}

Inside View #2 内部视图#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...
}

Backbone events are the way to go here. 骨干事件是这里的方式。 When you capture the event in the view, I would bubble it up using: 当您在视图中捕获事件时,我会使用以下命令将其冒泡:

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

Then, you should be able to capture this in your router initialise function, using: 然后,您应该能够在路由器初始化函数中捕获它,使用:

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

And then in the router declare a separate function: 然后在路由器中声明一个单独的函数:

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

I'm writing this from memory, so hopefully it make sense. 我是从记忆中写的,所以希望它有意义。 I've also not tested catching an event like this i the router, but it should work. 我也没有测试过像路由器这样的事件,但它应该可行。

HTH. HTH。

In the exact case you outline I would create a temp storage object on your global namespace and use that to transfer the data between your views, its a bit "hacky" but its better than using local storage, or the window object directly, at least with a temp object on your own global namespace the intent of the objects usage is known. 在你概述的确切情况下,我将在你的全局命名空间创建一个临时存储对象,并使用它来在你的视图之间传输数据,它有点“hacky”但它比使用本地存储更好,或者直接使用window对象,至少在您自己的全局命名空间中使用临时对象时,已知对象使用的意图。

I find it better to use the http://backbonejs.org/#Events for a similar purpose of passing data between two views, though it does depend on how you structure your pages, if you have two views on the page representing a "control" or "component" this approach works really well. 我觉得最好使用http://backbonejs.org/#Events来实现在两个视图之间传递数据的类似目的,尽管它确实取决于你如何构建页面,如果你在页面上有两个视图代表“控制“或”组件“这种方法非常有效。

If you post a link to your site or something I can have a look and give you some more help. 如果你发布了一个链接到你的网站或其他什么,我可以看看,并给你一些帮助。

Russ 拉斯

You could perhaps store it as a property on the view: 您可以将其存储为视图中的属性:

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

If your router can access both views, it can then simply pass the firstView.clickedHtml property to a function in the secondView (or to the initializer) 如果您的路由器可以访问两个视图,那么它可以简单地将firstView.clickedHtml属性传递给secondView (或初始化程序)中的函数

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM