2011-10-04 133 views
7

我在圈子里跑来跑去,似乎在我当前的应用程序中实施backbone.js中缺少一些东西。问题是我有一个主AppView,它初始化页面的各种子视图(图表,信息表等)。我的愿望是能够根据导航时传递的参数标志更改页面的布局。骨干视图嵌套

我碰到的情况是,在模板渲染后引用了dom元素的子视图在主AppView初始化过程中无法访问这些元素。所以主要的问题是如何确保适当的dom元素适用于每个事件绑定过程以正确设置?

如果我有一个事件绑定到我的LayoutView中的模型更改,则会显示布局,但后续视图无法正确呈现。我已经弄清楚的一些事情是将所有视图的'.el'值设置为html结构中的静态元素。这会使渲染发生,尽管这似乎脱离了利用'.el'提供的良好范围限制能力。

示例代码:

//Wrapped in jquery.ready() function... 
//View Code 
GraphView = Backbone.View.extend({ // init, model bind, template, supporting functions}); 

TableView = Backbone.View.extend({ // init, model bind, template, supporting functions}); 

LayoutView = Backbone.view.extend({ 
    initialize: function() { 
    this.model.bind('change:version', this.render, this); 
    }, 
    templateA = _.template($('#main-template').html()), 
    templateB = _.template($('#secondary-template').html()), 
    render: function() { 
    if ('main' == this.model.get('version')) { 
     this.el.html(this.templateA()); 
    } else { 
     this.el.html(this.templateB()); 
    } 
    }, 
}); 

MainView = Backbone.View.extend({ 
    initialize: function() { 
    this.layoutView = new LayoutView({ 
     el: $('#layoutContainer'), 
     model: layout, 
    }); 
    this.graphView = new GraphView({ 
     el: $('.graphContainer'), 
     model: graph 
    }); 
    this.tableView = new TableView({ 
     el: $('#dataTableContainer', 
     model: dataSet 
    }); 
    }, 
}); 

// Model Code 
Layout = Backbone.Model.extend({ 
    defaults: { 
    version: 'main', 
    }, 
}); 

Graph = Backbone.Model.extend({}); 
dataSet = Backbone.Model.extend({}); 

// Router code... 

// Fire off the app 
AppView = new MainView($('#appContainer')); 
// Create route, start up backbone history 

HTML: 为简单起见我只是重新安排了两个布局之间的div。

<html> 
    <head> 
    <!-- include above js and backbone dependancies --> 
    </head> 
    <body> 
    <script type="text/template" id="main-template"> 
     <div class="graphContainer"></div> 
     <div class="dataTableContainer"></div> 
     <div>Some other stuff to identify that it's the main template</div> 
    </script> 
    <script type="text/template" id="secondary-template"> 
     <div class="dataTableContainer"></div> 
     <div>Rock on layout version two!</div> 
     <div class="graphContainer"></div> 
    </script> 
    <div id="appContainer"> 
     <div id="nav"> 
     <a href="#layout/main">See Layout One</a> 
     <a href="#layout/secondary">See Layout Two</a> 
     </div> 
     <div id="layoutContainer"></div> 
    </div> 
    </body> 
</html> 

感谢您对任何人都有的见解/意见。谢谢!

+0

只是FYI,你的代码中有一堆拼写错误 - 假设它们是复制/粘贴问题,而不是实际的语法错误,是否安全? – nrabinowitz

+0

责备复制/粘贴,基本的逻辑,希望仍然被传达。感谢您指出了这一点。 – aztechy

回答

8

您的示例中有很多缺少的代码,但是如果我理解正确,则问题在于您尝试渲染依赖于由LayoutView生成的HTML的视图,但是在使用时会不同步地选择布局模型已更新,因此LayoutView尚未呈现。

有(与几乎所有骨干相关的)多种方法来此,但一般:

  • 如果我有谁依赖于一个“父”的观点被渲染的意见,我会把这些视图的实例化和渲染的责任放在父视图中 - 在这种情况下,LayoutView,而不是MainView

  • 如果父项异步渲染,则需要在回调中执行该实例 - 这里是LayoutView.render()方法。

,所以我可能构建这样的代码:

LayoutView = Backbone.view.extend({ 
    initialize: function() { 
    this.model.bind('change:version', this.render, this); 
    // you probably want to call this.model.fetch() here, right? 
    }, 
    templateA: _.template($('#main-template').html()), 
    templateB: _.template($('#secondary-template').html()), 
    render: function() { 
    if ('main' == this.model.get('version')) { 
     this.el.html(this.templateA()); 
    } else { 
     this.el.html(this.templateB()); 
    } 
    // now instantiate and render subviews 
    this.graphView = new GraphView({ 
     // note that I'm using this.$ to help scope the element 
     el: this.$('.graphContainer'), 
     model: graph 
    }); 
    this.tableView = new TableView({ 
     el: this.$('.dataTableContainer'), 
     model: dataSet 
    }); 
    // you probably need to call graphView.render() 
    // and tableView.render(), unless you do that 
    // in their initialize() functions 
    }, 
}); 

请注意,您不必在el通过在实例化 - 你可以在initialize()实例子视图,并设置el属性在subview.render()。您可以像现在这样在MainView.initialize()中实例化,并将视图传递给LayoutView以异步渲染。但我认为上述方法可能更清洁。

+0

感谢您的回复。我在渲染过程完成后调用了LayoutView中的子视图。假设各种子视图都有自己的渲染,这些渲染在模型更改状态中更新,这是正确的。 由于某些奇怪的原因,尽管它在我的抓取后似乎有些渲染调用被多次调用。引发我认为我多次无效地添加各种子视图。我想我可能只需要在获取我的数据后追踪其他可能导致多个呈现调用的内容。 再次感谢! – aztechy

+0

很高兴这有帮助 - 我经常发现,我需要逻辑来实例化一个子视图,只有在尚未加载时,这可能是问题。 (顺便说一句,如果你喜欢这个答案,你可以通过点击左边的复选标记来批准它:) – nrabinowitz

+0

对,需要创建逻辑来实例化子视图。我不幸遇到了一个问题,即在layoutView.render()中实例化子视图导致在其初始化设置中定义的模型更改事件上键入的子视图无法正确呈现。主要是在视图的模型状态在导航中保持不变的情况下,由于上述过程,该特定子视图似乎被空模板覆盖。我认为这可能需要重新处理事件逻辑。 – aztechy