骨干视图嵌套

azt*_*chy 8 javascript jquery backbone.js underscore.js

我正在圈子里跑来跑去,似乎在我目前正在实施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
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

欣赏你们任何人可能拥有的洞察力/输入.谢谢!

nra*_*itz 8

您的示例中有很多缺少的代码,但如果我理解正确,则问题是您正在尝试呈现依赖于生成的HTML的视图LayoutView,但是在更新模型时会异步选择布局,因此LayoutView还没有渲染.

有(就像几乎所有与Backbone相关的)多种方法,但总的来说:

  • 如果我有依赖于渲染的"父"视图的视图,我将负责在父视图中实例化和渲染这些视图 - 在这种情况下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
  },
});
Run Code Online (Sandbox Code Playgroud)

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