虽然我最近的大部分工作主要是使用Ruby on Rails和自由剂量的Javascript (主要是jQuery),但我想构建一个单页面应用程序,并意识到Ember.js似乎是一个新兴的流行框架来处理这类应用程序。
从各种文档和教程中可以看出,与Ruby on Rails或其他典型的服务器端框架相比,Ember.js需要一种非常不同的方式来思考如何解决问题。使用Ruby on Rails这样的框架,随着时间的推移,人们对“事物应该如何工作”的某些假设似乎可能会阻碍人们真正理解和接受“Ember way”。
Ruby on Rails开发人员在尝试学习Ember时应该消除哪些先入为主的观念?Ruby on Rails开发人员应该考虑的最具创新性和最重要的Ember概念是什么?
提前感谢!
发布于 2013-04-10 22:47:05
我将尽最大努力在StackOverflow的精神下回答这个问题,列出Ember和Rails之间的一些主要技术差异。我将把更具哲学意义的方面留给programmers.stackexchange.com的其他人。
您可以在working jsFiddle中找到下面的所有代码示例,前提是它可以帮助您可视化所有内容是如何组合在一起的。
集合和对象的单独路由
Ember和Rails之间的一个主要区别是集合路由(管理对象列表)和项目路由(管理单个对象)之间的关系。在Rails中,这些都是由单个资源控制器处理的。在Ember中,这些通常由两个不同的路由处理,因为它们操作两个不同的数据结构:
App.Router.map(function () {
this.route("posts", { path: "posts" });
this.route("post", { path: "post/:post_id" });
});
App.PostsRoute = Ember.Route.extend({
model: function (params) {
return App.Post.find();
}
});
App.PostRoute = Ember.Route.extend({
model: function (params) {
return App.Post.find(params.post_id);
}
});路由vs.控制器vs.视图vs.模板
在Rails中,您的代码分为三个主要的类组:
controller.
请求、加载和操作模型、呈现视图。
在Ember中,责任的分解是相当不同的。
模型。 Ember模型的工作方式与Rails模型非常相似。
App.Post = DS.Model.extend({
title: DS.attr("string"),
body: DS.attr("string"),
comments: DS.hasMany("App.Comment")
});路由。路由表示应用程序中用户可见的位置,它们与/post/7或/about等URL相对应。正如您在上面的代码示例中所看到的,路由在Ember中做得更多。最重要的是,它们查找与给定URL相对应的模型。它们还负责连接适当的控制器和视图,稍后您将看到这一点。
Controllers.控制器和Rails完全不一样!关于Ember控制器,需要理解的两件最重要的事情是:(1)它们基本上是模型对象的智能代理,(2)它们通常是单例。所以你将只有一个PostController,它将连接到你现在正在查看的任何帖子。
一般来说,您可以使用Ember控制器来管理不属于URL或数据库的瞬态。下面是一个例子:
App.PostController = Ember.ObjectController.extend({
// This shared between all posts for as long as the app runs (because
// this controller is a singleton), but it doesn't get saved in the database
// (because this is a controller, not a model).
lowRatedCommentsShown: false,
// Called by PostView or its template in response to an HTML event.
showLowRatedComments: function () {
this.set("lowRatedCommentsShown", true);
},
// Called by PostView or its template in response to an HTML event.
hideLowRatedComments: function () {
this.set("lowRatedCommentsShown", false);
}
});由于Ember控制器是模型周围的代理,它们也倾向于积累几乎属于模型的逻辑,但感觉与应用程序中的特定屏幕联系得太紧密。
视图和模板。 Ember视图和模板协同工作。最好将它们看作是一个GUI小部件。
App.PostView = Ember.View.extend({
// This can be omitted when we're created by a route.
templateName: 'post'
// Any HTML event handlers would go here if we needed them. Our job is to
// map between HTML events and events understood by the controller.
//doubleClick: function (evt) {
// // We'll actually bind this to a specific button, not a click event.
// this.get("controller").send("showLowRatedComments");
//}
});我们的post模板自由地混合了模型定义的字段和控制器定义的字段:
<script type="text/x-handlebars" data-template-name="post">
<h2>{{title}}</h2>
<div class="body">{{body}}</div>
{{#if lowRatedCommentsShown}}
<button {{action 'hideLowRatedComments'}}>Hide Low-Rated Comments</button>
{{else}}
<button {{action 'showLowRatedComments'}}>Show Low-Rated Comments</button>
{{/if}}
{{partial "comments"}}
</script>请注意,当我们的模型或控制器上的字段发生变化时,视图将自动重新呈现HTML中需要更新的部分!
异步行为、计算属性和绑定
因为Ember.js在浏览器中运行,所以许多操作都是异步的。Ember的大部分基础设计都是基于让异步更新变得愉快和简单。这种情况的一个关键后果是异步加载对象。当你调用find时,你会得到一个卸载的对象:
post = App.Post.find(params.post_id)
post.get("isLoaded"); // -> false
post.get("title"); // -> not yet available当服务器向您发送数据时,您将看到:
post.get("isLoaded"); // -> true
post.get("title"); // -> "Post #1"为了让这一切变得轻松,Ember严重依赖于computed properties,observers和bindings。在上述每种情况下,关键思想都是对数据的更改应该自动波及整个系统。例如,我们可以使用计算属性来确保在评论的rating发生更改时随时更新isLowRated:
App.Comment = DS.Model.extend({
post: DS.belongsTo("App.Post"),
body: DS.attr("string"),
rating: DS.attr("number"),
isLowRated: function () {
return this.get("rating") < 2;
}.property("rating") // A list of properties we depend on.
});请注意,Ember的Handlebar模板与此系统深度集成。当您在模板中编写{{title}}时,您将建立一个绑定,该绑定将在title发生更改时自动更新DOM。在编辑字段的情况下,此绑定在两个方向上都有效!对显示值的更改将被直接推回到模型中(尽管可以使用事务回滚它)。
同样值得记住的是,许多动态更新--特别是绑定--在当前“运行循环”的末尾异步运行。这就是为什么您经常会在测试套件中看到对Ember.run的调用:
Ember.run(function () {
// Change some bindings here. Not all changes will propagate immediately.
});
// Test that the values have all propagated here, after the run loop is done.在实践中,Ember感觉比Rails异步得多,但不如Node.js这样的事件系统异步。这是因为大多数异步更新都是由绑定自动管理的。
幸存的Ember数据
这是一个我将偏离严格的技术细节并提到一些实用建议的地方。Ember Data提供了DS.Model,如上所示。它并不是Ember.js的唯一模型层--查看ember-rest、ember-resource和类似的库以获取替代方案。目前,Ember数据还没有正式发布,但如果你想生活在前沿,可以在生产应用程序中非常谨慎地使用它。一些小贴士:
hasMany关系的完整ID列表。如果你正在使用Rails,请参阅active_model_serializers。使用Ember数据可以获得非常好的结果。但它远没有ActiveModel成熟,需要这样对待它。
https://stackoverflow.com/questions/15913324
复制相似问题