Ember.js - 应该在哪里存储接口状态?

Gab*_*ant 7 javascript ember.js ember-old-router

是否存在关于接口状态(与持久模型状态相对)应该存在于Ember.js应用程序中的官方故事?

路由器文档的"响应用户启动的事件"部分中,有一个将点击事件委托给照片的"showPhoto"方法的示例,但是模型"显示"本身似乎是一种不合需要的混合关注点.

我知道在许多情况下,状态应该存储在路由器中,以便接口状态在URL中表示,并在刷新页面或将URL发送给某人时恢复.但是非分层状态呢,例如页面上选择的项目列表呢?

理想情况下,该类型的状态将被序列化为查询/哈希参数(例如:http://www.hipmunk.com/flights/QSF-to-NYC#!dates=Sep15,Sep16p1;kind=flight&locations=QSF,YYZ&dates=Sep15 ,Sep23~tab = 1)但据我所知,路由器不提供该功能,是吗?

在BackboneConf,Jeremy Ashkenas说在Backbone中做到这一点的正确方法是将状态存储在模型上(他有一个带有"选定"字段的模型的例子).但是我相信汤姆戴尔说他认为这不是一个好主意,而不是在Ember应该怎么做.不幸的是,我不记得他提到应该怎么做.

Dan*_*rdt 4

如果您希望状态可路由(即可通过 url 访问),则需要通过 ember 的路由器可序列化和反序列化。如果状态是瞬态的且不可路由,那么最好将其保留在控制器上。

如果您需要跨多个模型表示复杂的接口状态(例如,选择列表中的项目),请考虑维护包装底层数据模型的特定于控制器的对象数组。我认为直接在模型上表示视图状态是很hackish的,特别是当这些模型跨多个视图使用时。

对于您提供的示例,您可能会执行以下操作来连接复杂的路线:

Ember.Route.extend({
  route: "flights/:cities/dates/:dates",

  serialize: function(router, context){
    return {cities: context.get('cities'),
            dates:  context.get('dates')};
  },

  deserialize: function(router, params){
    // return a context object that will be passed into connectOutlets()
    return {cities: params.cities,
            dates:  params.dates};
  },

  connectOutlets: function(router, context) {
    // pass the context from deserialize() in as the content of a FlightController
    router.get('applicationController').connectOutlet('flight', context);
  }
})
Run Code Online (Sandbox Code Playgroud)

请注意,您还可以使用诸如“flights?cities=:cities&dates=:dates”之类的路线,但上面的路线可能更干净且更适合 SEO。


在 Gabriel 的评论后进行扩展:如果您想维护一个搜索数组,每个搜索都位于其自己的选项卡中,我建议将这些搜索的数据保留在应用程序级数组中(例如 App.currentUser.activeSearches)。我的理由是,您不希望每次用户切换选项卡时都重新创建此数据。相反,路由器会检索此数据deserialize(),然后将其作为上下文传递给connectOutlets()。切换选项卡时,应基于该对象快速重新构建表示该数据的视图和控制器。让我扩展上面的例子:

Ember.Route.extend({
  route: "flights/:cities/dates/:dates",

  serialize: function(router, context){
    return {cities: context.get('cities'),
            dates:  context.get('dates')};
  },

  deserialize: function(router, params){
    // find or create a "Search" object that contains the filters and results,
    // which will be passed into connectOutlets()
    return App.currentUser.findOrCreateSearch({cities: params.cities,
                                               dates:  params.dates});
  },

  connectOutlets: function(router, context) {
    // pass the context (a search object) from deserialize() in as the content of a FlightController
    router.get('applicationController').connectOutlet('flight', context);
  }
})
Run Code Online (Sandbox Code Playgroud)