首页 > 解决方案 > 在 Ember.js 中组织列表、查看、创建和更新路由的最佳实践

问题描述

现在使用 ember.js 工作了几年,我仍然不太清楚,什么应该被视为构建列表、查看、创建和更新路由的最佳实践。

到目前为止,我使用的项目主要用于为每个实体路由树。用于列表的复数实体名称与用于创建的子路径和用于详细视图的单数实体名称与用于编辑的子路径。例如,post模型将具有以下路由:/posts用于列出帖子、/posts/new用于创建功能、/post/:post_id用于显示单个帖子和/post/:post_id/edit用于编辑该帖子。相应的路由器看起来像这样:

Router.map(function() {
  this.route('post', { path: '/post/:post_id' }, function() {
    this.route('edit');
  });
  this.route('posts', function() {
    this.route('new');
  });
});

这种方法非常适合细节和编辑视图,因为它们共享相同的模型。所以编辑路径的模型钩子可以重用细节视图路径的模型。在 ember 代码中,如下所示:

// app/routes/post.js
import Route from '@ember/routing/route';

export default Route.extend({
  model({ post_id }) {
    return this.get('store').findRecord('post', post_id);
  }
});

// app/routes/post/edit.js
import Route from '@ember/routing/route';

export default Route.extend({
  model() {
    return this.modelFor('post');
  }
});

通常我们会从posts路由模型钩子返回一组帖子,而不是实现路由模型钩子posts.new(或者根据架构返回 POJO / Changeset,但这不是这里的问题)。假设我们没有实现posts.new路由的模型钩子,看起来像:

// app/routes/posts.js
import Route from '@ember/routing/route';

export default Route.extend({
  model({ post_id }) {
    return this.get('store').findAll('post');
  }
});

// app/routes/posts/new.js
import Route from '@ember/routing/route';

export default Route.extend({
});

但是现在这种方法不再有效,因为在加载posts.new集合之前,向路由的转换被阻塞。posts因为我们不需要这个集合来创建帖子列表(至少如果我们只在posts.index路由中而不是在所有子路由中显示它们)这感觉不对。

对那些不熟悉 ember 的人的旁注:嵌套路由模型钩子按顺序执行。所以在我们的例子中,首先是应用程序路由的模型钩子,然后是发布路由,然后是 post.new 路由等待其中一个执行的任何承诺。

那么什么应该被视为最佳实践呢?

对此有任何想法将不胜感激。决定不在社区 slack 中问这个问题,以更好地记录答案。

标签: ember.jssoftware-design

解决方案


在 ember 中嵌套路由的要点是将子路由的输出嵌套在父路由中。虽然您当前的结构有效,但它与 ember 的结构化路由功能并不匹配。

您应该使用带有明确定义的索引路由的单一嵌套路由

在每一层嵌套(包括顶层),Ember 自动为 / 路径命名的 index 提供一个路由。要查看何时出现新的嵌套级别,请检查路由器,每当您看到一个函数时,这就是一个新的级别。

Router.map(function() {
  this.route('posts', function() {
    this.route('favorites');
  });
});

相当于

Router.map(function() {
  this.route('index', { path: '/' });
  this.route('posts', function() {
    this.route('index', { path: '/' });
    this.route('favorites');
  });
});

如果你创建一个明确的 posts/index.js 文件,它可以用作你的列表路由。这样做将帮助您避免在转换到创建路由之前获取所有帖子的问题。

虽然与您目前拥有的结构不同,但我建议以下内容。

Router.map(function() {
  this.route('posts', function() {
      this.route('index');  // /posts  - posts/index.js
      this.route('new');    // /posts/new - posts/new.js
      this.route('view', { path: '/:post_id' }  // /posts/1234 - posts/view.js
      this.route('edit', { path: '/:post_id/edit' }  // /posts/1234/edit - posts/edit.js
  }); 
});

根据new和edit中逻辑的复杂程度,可以考虑将两条路由合二为一,或者在生成空模型后简单的将new转为edit。

这样做的好处包括:

简单性 您不必为所有路线重新定义路径。一切都属于posts/,并且路线指定了下一块。

一致性 JSONapi 模式使用复数路由来获取集合和单个对象。

逻辑包装 如果您使用显式 index.js 文件,则可以使用旧的 posts.js 文件作为 post 命名空间内所有项目的通用包装器。Posts.js 将有一个插座,用于放置索引、新建、编辑和查看路由

如果您需要您的视图和编辑路线来共享相同的模型生成,您可以将您的视图/编辑嵌套到一个公共组中,以便它们共享一个父模型。

this.route('posts', function() {
    this.route('post', { path: '/:post_id' }, function() {
        this.route('view', { path: '/' }) ;
        this.route('edit', { path: '/edit' });
    })
})

推荐阅读