Ember博客应用 #

一、项目概述 #

1.1 功能需求 #

  • 文章列表展示
  • 文章详情查看
  • 文章创建/编辑
  • 文章删除
  • 用户认证
  • 评论功能

1.2 技术栈 #

  • Ember.js 5.x
  • Ember Data
  • Ember CLI
  • Mirage (模拟API)

二、项目初始化 #

2.1 创建项目 #

bash
ember new blog-app
cd blog-app
ember install ember-cli-mirage

2.2 配置路由 #

javascript
// app/router.js
Router.map(function () {
  this.route('home', { path: '/' });
  this.route('posts', function () {
    this.route('new');
    this.route('show', { path: '/:post_id' });
    this.route('edit', { path: '/:post_id/edit' });
  });
  this.route('login');
  this.route('register');
});

三、数据模型 #

3.1 Post模型 #

javascript
// app/models/post.js
import Model, { attr, belongsTo, hasMany } from '@ember-data/model';

export default class PostModel extends Model {
  @attr('string') title;
  @attr('string') body;
  @attr('string') excerpt;
  @attr('date') createdAt;
  @attr('date') updatedAt;
  @attr('boolean') isPublished;
  @belongsTo('user') author;
  @hasMany('comment') comments;

  get formattedDate() {
    return this.createdAt?.toLocaleDateString('zh-CN');
  }
}

3.2 User模型 #

javascript
// app/models/user.js
import Model, { attr } from '@ember-data/model';

export default class UserModel extends Model {
  @attr('string') name;
  @attr('string') email;
  @attr('string') avatar;
}

3.3 Comment模型 #

javascript
// app/models/comment.js
import Model, { attr, belongsTo } from '@ember-data/model';

export default class CommentModel extends Model {
  @attr('string') body;
  @attr('date') createdAt;
  @belongsTo('user') author;
  @belongsTo('post') post;
}

四、路由实现 #

4.1 文章列表 #

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

export default class PostsRoute extends Route {
  model() {
    return this.store.query('post', {
      filter: { isPublished: true },
      include: 'author',
      sort: '-createdAt',
    });
  }
}

4.2 文章详情 #

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

export default class PostsShowRoute extends Route {
  model(params) {
    return this.store.findRecord('post', params.post_id, {
      include: 'author,comments.author',
    });
  }
}

五、组件实现 #

5.1 文章卡片组件 #

javascript
// app/components/post-card.js
import Component from '@glimmer/component';

export default class PostCardComponent extends Component {
  get excerpt() {
    const body = this.args.post.body || '';
    return body.length > 150 ? body.substring(0, 150) + '...' : body;
  }
}
handlebars
{{! app/components/post-card.hbs}}
<article class="post-card">
  <LinkTo @route="posts.show" @model={{@post.id}}>
    <h2 class="post-title">{{@post.title}}</h2>
  </LinkTo>
  <p class="post-excerpt">{{this.excerpt}}</p>
  <footer class="post-meta">
    <span class="author">{{@post.author.name}}</span>
    <span class="date">{{@post.formattedDate}}</span>
  </footer>
</article>

5.2 文章表单组件 #

javascript
// app/components/post-form.js
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';

export default class PostFormComponent extends Component {
  @tracked title = this.args.post?.title || '';
  @tracked body = this.args.post?.body || '';
  @tracked isPublished = this.args.post?.isPublished || false;

  @action
  async submit(event) {
    event.preventDefault();

    const postData = {
      title: this.title,
      body: this.body,
      isPublished: this.isPublished,
    };

    if (this.args.onSubmit) {
      await this.args.onSubmit(postData);
    }
  }
}

六、总结 #

博客应用要点:

模块 技术
路由 Ember Router
数据 Ember Data
组件 Glimmer组件
样式 CSS

通过完整项目实践掌握Ember开发。

最后更新:2026-03-28