2

大多数处理主从场景的 Backbone 教程通过使用从路由传递的模型创建新视图来处理细节状态(示例)。我想知道替代选项是什么,每个选项的优缺点是什么。

这种实例化新视图的方法对我来说一直很突出的一点是,它似乎错过了利用 Backbone 的模型视图绑定的机会。即,创建基于所选模型更新的单个详细视图。但这需要一个单独的模型,只关注 UI / 活动状态。

我可以想到三种不同的模式:

  • 为每个活动细节创建/销毁视图。(这似乎是多余的工作,更不用说潜在的僵尸问题了)
  • 维护一个表示活动细节的附加模型,并创建一个在模型更新时重新呈现自身的视图
  • 使用交换关联模型的方法创建一个视图(我认为这会导致事件绑定问题并且可能不是一个好主意)

在像上面链接的示例教程这样的简单案例的上下文中,优点/缺点是什么?#2 中使用 UI 模型的想法是不好的做法吗?还有其他解决方案吗?

4

1 回答 1

1

In my experience, UI models have been incredibly helpful. We maintain a ContextModel for every "page" in our app. What makes it really nice is that we guarantee "pages" to be initialized with a complete ContextModel so there is only ever one place the context is originally created.

Our AppView always handles creating the initial context for a page when a specific route is triggered. The route handler would be where the defaults for a context are set, and things are parsed from the route's values.

Once the page itself has been initialized, it only has to worry about changes to the ContextModel and have handlers that do any updates necessary and then update the path.

Here's an example pulled directly from our AppView:

onSomeRoute : function (project, category, pivot, tab, item) {

  // Setup page context with defaults.
  var options = {
    category : 'traits',
    tab      : 'population',
    item     : null
  };

  // Figure out what the allowed categories and tabs are from this
  // environment by checking against all schema items.
  [snipped]

  // Resolve the `category` and the `pivot`. Try and match the pivot's
  // slug, else choose the first pivot in the category.
  if (_(categories).contains(category)) options.category = category;

  [snipped]

  if (pivots) options.pivot = pivots.find({ slug : pivot }) || pivots.first();

  // Resolve the `tab` and `item`. Only allow valid tabs, and then try
  // to match the item's slug as well, or choose the first one.
  var tabs = ['population', 'sources', 'engagement', 'retention'];
  if (_(tabs).contains(tab)) options.tab = tab;
  [snipped]

  // Now that we've applied some defaults, make sure the path is
  // updated to reflect what the interface is showing.
  [snipped]

  this.loadPage('some-page', options);
}

And then in the PageView in question we have a couple change handlers:

// When category changes, try to match the current pivot against pivots
// in the category, else choose the first pivot from the category.
onCategoryChange : function (context, category) {
  var schema = this.context.get('environment').get(category);
  if (!schema.contains(this.context.get('pivot')))
    this.context.set('pivot', schema.first());

  this.router.update({
    category : category
  });
},

// When the pivot changes, create a new set of segments for the context.
onPivotChange : function (context, pivot) {
  Segmenter.segment(context, function (segments) {
    context.get('segments').reset(segments).each(function (segment) {
      segment.evaluate();
    });
  });

  this.router.update({
    pivot : pivot.get('slug')
  });
},

Notice that all of the change handlers keep the URL for the page updated based on the changes in the context. (We wrote a couple custom methods on the router to make this really easy for us.) But they also do any other logic we need to have happen for the page.

Hopefully some of that helps give you ideas. In general, any state that is stored in the URL is in our PageContext and then a couple other things that are derived from that state are also stored there for convenience.

于 2012-07-23T18:24:45.063 回答