主干.js结构化嵌套视图和模型


71

使用骨干.js:

我有一个顶级ModelA,其中包含2个属性和2个嵌套模型ModelB和ModelC。ModelB和ModelC分别具有2个属性,如下所示:

ModelA
    attributeA1
    attributeA2
    ModelB
        attributeB1
        attributeB2
    ModelC
        attributeC1
        attributeC2

对于ModelA,有一个ViewA,对于ModelB,有一个ViewB。ViewA的render函数在主体上放置一个新的div,而ViewB的render创建一个h1。ViewA的初始化调用ViewB的渲染,以将h1插入新的div中。这种分离的基本原理是h1可能会更改,并且需要独立于ViewA进行重新渲染。

ViewA
    initialise: 
        //call ViewA's own render function
        this.render() 

        //call ViewB's render function that further modifies the $("#new") div created earlier.
        $("#new").append(ViewB.render().el)

    //ViewA's own render function
    render: //place <div id="new"></div> onto 'body'

ViewB
    render: //create a <h1></h1>
    funcB1: //can this access it's parent ModelA's attributes and other objects?

Q1:ViewB具有功能funcB1。此函数可以访问其父模型的属性吗?属性,例如attributeA1,甚至attributeC1(将是同级/表兄弟)?

Q2:作为对Q1的进一步扩展,funcB1可以访问与ViewA相关的DOM元素吗?(在此示例中,为#new div?)

问题3:通常,我如何如上所述定义视图和模型之间的关联,以便所有内容正确地结合在一起?

我意识到这个问题有点抽象,但是任何人都希望得到任何帮助或指导。


1
您是否尝试过编写测试以查看这些测试是否回答了您的问题?
Spoike 2011年

我尝试使用Q1和Q2的一些代码,但无法使其正常工作。我认为最好的方法就是伪代码,并允许更多的精通Java的人指出正确的方向。
fortuneRice 2011年

我建议您用失败的代码编写单独的问题,以便js程序员指出问题所在。
Spoike 2011年

当然,这很公平,我会尝试写一些。无论如何,如果仍然有人想提供任何输入,仍然欢迎!
fortuneRice 2011年

1
这里有一个相关的(虽然更通用的)问题和答案长有关此进一步了解:stackoverflow.com/questions/10077185/...
乙Robster

Answers:


73

为了能够获得相关模型的属性,该模型必须具有与之相关的某种模型的知识。Backbone.js不会隐式处理关系或嵌套,这意味着您必须自己确保模型之间相互了解。要回答您的问题,一种解决方法是确保每个子模型都有一个“父”属性。这样,您可以先遍历嵌套,再遍历父层次,然后遍历所有您知道的兄弟姐妹。

详细说明您的问题。初始化modelA时,您可能正在创建modelB和modelC,建议这样做时设置指向父模型的链接,如下所示:

ModelA = Backbone.Model.extend({

    initialize: function(){
        this.modelB = new modelB();
        this.modelB.parent = this;
        this.modelC = new modelC();
        this.modelC.parent = this;
    }
}

这样,您可以通过调用this.parent来访问任何子模型函数中的父模型。

关于您的视图,当执行嵌套的主干视图时,我发现使用视图的tagName选项使每个视图代表一个HTML标签更加容易。我会这样写你的观点:

ViewA = Backbone.View.extend({

    tagName: "div",
    id: "new",

    initialize: function(){
       this.viewB = new ViewB();
       this.viewB.parentView = this;
       $(this.el).append(this.viewB.el);
    }
});

ViewB = Backbone.View.extend({

    tagName: "h1",

    render: function(){
        $(this.el).html("Header text"); // or use this.options.headerText or equivalent
    },

    funcB1: function(){
        this.model.parent.doSomethingOnParent();
        this.model.parent.modelC.doSomethingOnSibling();
        $(this.parentView.el).shakeViolently();
    }

});

然后在您的应用程序初始化代码中(例如在您的控制器中),我将启动ViewA并将其元素放置在body元素内。


我有一个问题是否可以。在initialize回答开始时在ModelA的方法中创建modelB时,应该设置this.set('modelB') = new ModelB();它还是可以在这种情况下不使用setter方法?
David Tuite 2011年

1
如果希望该关系位于模型的属性中(例如,能够绑定到更改事件),则可以使用setter方法。语法为this.set({modelB:new ModelB()})。但是,如果您想执行更复杂的关系映射,我强烈建议Paul Uhitol或其他一些用于ribs.js的关系映射插件来进行骨干关系。
詹斯·阿尔姆

8
是否由于创建循环引用而导致任何内存泄漏?
Scott Greenfield

1
请注意,如果ViewA具有render方法,那么在您的initialize方法中将B.el附加到A.el将会被破坏;您的示例仅能起作用,因为父级是无渲染视图。
铁氟龙泰德

1
没错,这是一个警告。我仅将其用于类似控制器的视图
Jens Alm 2013年

3

对于“我可以”的问题的一般答案始终是“是的,只要您愿意编写代码”。Backbone背后的目的是提供模型和视图的强烈分离。如果B1引用了A1,而A1引用了C1,则您完全有能力创建方法和设置规则,以便B1可以修改A1和C1,依此类推。

应将视图设置为从其各自的模型接收CRUD事件。如果用户对B1view进行了修改B1model的操作,而B1model又对A1model进行了修改,则A1model应生成一个事件,A1view接收该事件并导致A1view的重新呈现,依此类推。它应该像魔术一样发生。(在实践中,正确解决魔术需要花费一些时间,但是我发现Backbone确实非常强大。BackboneRelational可以帮助您解决此处所描述的问题。)


14
谢谢。我认为对此的更准确答案应该是“是的,只要您愿意并且能够编写代码”!
fortuneRice 2011年

3

上面的解决方案是正确的,但存在一些问题。

initialize: function(){
  this.viewB = new ViewB();
  this.viewB.parentView = this;
  $(this.el).append(this.viewB.el);    
}

现在,主要是模型的toJSON()返回陈旧的数据。我已经在ribs.js插件中发布了解决此问题的解决方案。欢迎您使用它。


2

您可以使用一些扩展名,例如Backbone-Forms https://github.com/powmedia/backbone-forms。要遵循您的用例,请定义类似以下的架构:

var ModelB = Backbone.Model.extend({
    schema: {
        attributeB1: 'Text',
        attributeB2: 'Text'
    }
});

var ModelC = Backbone.Model.extend({
    schema: {
        attributeC: 'Text',
    }
});

var ModelA = Backbone.Model.extend({
    schema: {
        attributeA1: 'Text',
        attributeA2: 'Text',
        refToModelB: { type: 'NestedModel', model: ModelB, template: 'templateB' },
        refToModelC: { type: 'NestedModel', model: ModelC, template: 'templateC' }
    }
});

查看https://github.com/powmedia/backbone-forms#customising-templates中的部分模板。

这里的重要部分是type: 'NestedModel'template: 'templateXXX'

该插件有一些限制,但是您可以在https://github.com/documentcloud/backbone/wiki/Extensions%2C-Plugins%2C-Resources中查看其他限制。


0

有骨干插件Backbone-relational.js,它为Backbone提供模型之间的一对一,一对多和多对一关系。

我认为这个js将满足您的需求。Vist BackboneRelational有关更多文档。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.