本文为翻译文章:
译者:Jacky <jacky@iajax.net>
译者博客:http://blog.csdn.net/varkychan
原文:http://guides.sproutcore.com/getting_started.html
译者前言:由于国内关于SproutCore的中文资源比较少,所以我开始尝试翻译官方网站的相关教程及指南,因为本人英文水平真的一般,语文水平也不咋的,所以在译文可能表达得不清晰,甚至是误译的可能,所以发现问题,请不啬向我指点,吾将非常感激!
SproutCore入门教程 – 第一部分
入门
读完本章后,你将能够:
- 使用SproutCore的模板描绘你的应用界面
- 委托处理视图(view)用户事件
- 当模型(models)发生改变时通过绑定(bindings)更新视图(views)
通过使用SproutCore从头开始创建一个真实的“代办事项(Todo list)”应用程序,你将学到所有这些内容。
1 跟随
你可以在Github上看到这个应用程序最后完成的源代码。要看运行的效果,点击这里。
这里还有一个截屏视频放在Vimeo上。
2 安装SproutCore
这个指南假设你已经安装了SproutCore。如果你还没安装,请现在安装它。
这份指南需要安装SproutCore 1.6.0 beta版。安装程序在Windows和Mac上都有提供,如果你通过RubyGems来安装,就需要使用 gem install sproutcore –pre 来安装beta版本。
3 创建新应用
首先,通过如下命令生成一个基于HTML的新应用。
$ sc-init todos –template
这里会创建几个应用程序需要用到的文件,放在 apps/todods 文件夹内。
- apps/
-
- todos/
- todos.js – 在这里定义model,view及controller.
- resources/
- templates/ – 将所有的Handlebars模板放在这里.
- todos.handlebars – 应用程序的主模板.
- images/ – 图片文件放在这里.
- stylesheets/ – 样式(CSS)文件放在这里.
- todos.css – 应用程序的主样式文件.
- templates/ – 将所有的Handlebars模板放在这里.
- tests/
- todos/
- Buildfile – 告诉SproutCore如何创建你的应用程序. 通常, 你只要使用默认提供的即可.
- README – 对项目的说明.
现在打开todos.js文件. 你将会看到如下代码:
apps/todos/todos.js
Todos = SC.Application.create();
SC.ready(function() {
Todos.mainPane = SC.TemplatePane.append({
layerId: “todos”,
templateName: “todos”
});
});
代码中为你的应用程序创建了一个命名空间Todos,然后增加一个新的pane模板。pane负责事件委派和把模板放到DOM中,你会在后面的内容中了解到更多关于这些方面的内容。
如果你向sc-init传递一个驼峰式的名字,如ToDos(注意这里的大写字母D),这时命名空间是ToDos,而文件夹的名称则是将命名空间进行下划线分隔,如apps/to_dos。
4 定义模型(model)
在这个教程中,我们要创建一个列表,用于管理代办事项(todos)。用户能够创建某个任务的新代表事项,然后在任务完成后可以剔除它。
首先让我们定义一个model,它是由SC.Object派生出来的新子类:
apps/todos/todos.js
Todos = SC.Application.create();
Todos.Todo = SC.Object.extend({
title: null,
isDone: false
});
SC.ready(function() {
Todos.mainPane = SC.TemplatePane.append({
layerId: ‘todos’,
templateName: ‘todos’
});
});
请在建立Todos对象的代码下面插入新代码。
现在我们已经定义了一个具有两个属性的类,这两个属性分别是:title:字符串类型;isDone:布尔类型。
5 使用Controller管理Model
现在我们知道我们的数据是怎样的了,然后我们创建一个controller来管理它。因为我们想要管理一个有序的代办事项列表,因此我们将使用SC.ArrayController来实现它。
in apps/todos/todos.js
// 在文件未尾加入以下代码
Todos.todoListController = SC.ArrayController.create({
// 以一个空数组初始化数组控制器.
content: []
});
在像 SproutCore 这样的MVC框架中,controller层是作为模型(model)层(只与表示数据的对象相关)和视图(view)层(只与这些对象的显示相关)的沟通桥梁。
现在已经有了一个没有数据的数组控制器,让我们增加一个创建新代办事项的方法:
in apps/todos/todos.js
// 更新上面的代码
Todos.todoListController = SC.ArrayController.create({
// 以一个空数组初始化数组控制器.
content: [],
// 用参数title创建一个新代办事项,然后增加到数组中
createTodo: function(title) {
var todo = Todos.Todo.create({ title: title });
this.pushObject(todo);
}
});
SC.ArrayController 扮演content数组的代理角色,对ArrayController所作的修改会反映到content数组上。
6 用文本框(Text Field)创建新代办事项
我们已经提供了一个简单的样式文件,用于对应用程序进行一些装饰。你应该下载这个CSS文件,然后把sc-init为我们生成的空文件 apps/todos/resources/stylesheets/todos.css 替换掉。
目前我们已经建立了model和controller,现在让我们进入到有趣的部分:为我们的用户创建界面。第一步就是创建一个文本框,用于让用户输入代办事项的内容。SproutCore的TemplateView使用Handlebars模板来快速定义应用程序的界面。虽然Handlebars可以容易快速的标注HTML代码,但你将会看到,它已经得到扩展,你只需要花很少的努力就能够充分发挥它的优势。
在架设界面之前,先让我们打开 resources/templates/todos.handlebars 文件。你将会看到初始位居于文件中的HTML片段:
apps/todos/resources/templates/todos.handlebars
<h1>Welcome to SproutCore!</h1>
用下面的HTML代码替换它:
apps/todos/resources/templates/todos.handlebars
<h1>Todos</h1>
<input id=”new-todo” type=”text”
placeholder=”What needs to be done?” >
要获得更多关于Handlebars的信息,请访问Handlebars网站。要学习更多关于在SproutCore中使用Handlebars的信息,请阅读使用Handlebars模板指南。
现在我们已经有了model,view及controller,是时候在浏览器中打开我们的程序,然后看看它会是怎么样的。
在开发过程中,sc-server让测试应用程序变得非常简单,只需要在项目文件夹里运行以下命令即可:
$ sc-server
Starting server at http://0.0.0.0:4020 in debug mode
To quit sc-server, press Control-C
>> Thin web server (v1.2.1 codename Bat-Shit Crazy)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4020, CTRL+C to stop
然后打开网页浏览器访问http://localhost:4020/todos地址,你将会看到应用程序在加载,只要你确认应用程序已经启动并运行,就可以开始分析SproutCore是如何处理<input>标签(上面加入的文本框)的事件了。当用户在文本框中输入内容并按回车键,程序就会创建一个新的代办事项,然后插入到控制器的content数组中。
在SproutCore中,视图对象是负责更新DOM和处理事件的。除此之外,它还允许我们缓存对DOM作出的改动以获得最大的性能,以及为常见的跨平台事件处理提供支持。无论何时,只要你想显示动态内容或处理事件,你就会用到视图对象。
in apps/todos/todos.js
// 在 SC.ready 之前
Todos.CreateTodoView = SC.TextField.extend({
insertNewline: function() {
var value = this.get(‘value’);
if (value) {
Todos.todoListController.createTodo(value);
this.set(‘value’, ”);
}
}
});
由于 CreateTodoView 中包含一个文件框,所以我们创建一个 SC.TextField 的子类,它为我们提供了几个方便使用文本框的方式。例如,你可以访问 value 属性、在用户按下回车键时响应如 insertNewLink 这样的高层事件。
界面已经定义好了,现在我们需要把它加入到Handlebars模板的HTML代码中去。
像下面这样把<input>标签包起来:
apps/todos/resources/templates/todos.handlebars
<h1>Todos</h1>
{
{#view Todos.CreateTodoView}}
<input id=”new-todo” type=”text”
placeholder=”What needs to be done?” />
{
{/view}}
#view是Handlebars的区块助手程序(block helper),它给SC.TemplateView分配一块HTML代码。这就意味着在特定视图中描述的行为,如事件处理,将与区块(block)中的HTML关联。
现在我们有了创建代办事项的界面,接下来我们建立一个界面把创建的代办事项显示出来。我们将使用到Handlebars的#collection助手程序(helper)来显示一个代办事项列表。#collection将创建一个SC.TemplateCollectionView实例,这个实例会使用内附的HTML代码来呈现它的基础数组(underlying array)中的每个条目。
in apps/todos/resources/templates/todos.handlebars
<!– 在文件的末尾 –>
{
{#collection SC.TemplateCollectionView ¬
contentBinding=”Todos.todoListController”}}
{
{content.title}}
{
{/collection}}
我们使用了后续符( ¬)来标明不要回车的代码行。(说明:为了印刷的需要,一行太长的代码行要分成多行显示,而这行代码必须在一行内完成,不能分行,故使用后续符来标明本行与接下来的一行是同一行代码)。
注意,我们还让collection将属性content与todoListController控制器进行了绑定。对于数组控制器中的每个项目,collection都会创建一个新的子视图(child view)去显示模板{
{content.title}}的内容。
你可以通过创建一个名字以Binding结尾的属性来建立绑定关系。通过这种方式,我们将Todos.todoListController和collection视图的content属性进行了绑定。当绑定的其中一端发生了改变,SproutCore就会自动更新另外一端。
现在最好再去浏览一下 http://localhost:4020/todos(或者刷新一下,如果你还打开着),你会发现它看起来跟之前没有什么变化。试试在文本框中输入一些文本然后按回车。看到了吗?一旦我们创建了一条新代办事项并插入到数组控制器中,视图就会立即自动更新。
你现在已经看到SproutCore的小小威力了。通过使用SproutCore的绑定功能把数据和视图建立起关系,你就只需要对数据层进行操作而把更新视图层的艰苦工作留给SproutCore为你完成。
事实上这就是SproutCore的一个核心概念,而不是演示的效果。SproutCore绑定系统的设计是从视图系统的考虑出发的,这使得你只要直接对数据进行操作而不需要操心于手动保持视图层同步。你会在这个指南的其它部分或其它教程中反复看到这个概念。
7 把事情做完
现在已经可以增加代办事项了,但却还不能把它标记为完成。为了舒缓因此而产生的无终止的代办事项使我们产生的挫败感,先让我们为它增加能够标记代办事项为完成状态的功能。
首先要做的就是在每个代办事项上增加一个复选框(checkbox),如前面所提到的,如果想要处理像用户输入这样的事件,就需要一个视图来管理HTML部分。既然如此,我们就添加一个复选框(checkbox)并且在用户对它的值作出更改时获得通知。记住,我们可以在模板中使用#view助手程序来分配视图并提供HTML内容。而且,我们还能够使用view助手程序来引用为其本身提供HTML内容的视图 (注意,没有#号)。例如,我们可能想要创建一个相对复杂的可被重复利用的视图,还有在需要更新的时候我们不想更新全部的模板。在todos.handlebars中,更新后的代办事项看起来像这样:
in apps/todos/resources/templates/todos.handlebars
<!– 替换前面的代码 –>
{
{#collection SC.TemplateCollectionView ¬
contentBinding=”Todos.todoListController”}}
{
{view Todos.MarkDoneView}}
{
{/collection}}
现在让我们实现刚刚提到的Todos.MarkDoneView视图。因为视图中实现了一个复选框,所以我们需要从SC.Checkbox控件派生一个新子类。它给视图提供一个value属性以反映DOM中的值,一个title属性以显示复选框的标签。
深入分析,SproutCore向change事件绑定一个处理程序,然后当事件发生时更新value属性值。为了兼容不同的浏览器,这种情况可能会变,但如果你只与SproutCore属性打交道,那你就不用担心这些问题了。
对于SC.TemplateCollectionView基础数组内的每个项目,SC.TemplateCollectionView会创建一个新的子视图,子视图中的content属性包含视图要显示的对象。在我们的例子中,每个代办事项就是一个子视图,然后每个子视图的content属性都设置了对应的Todo对象。
这样就可以很容易对复选框中的属性与我们呈现的Todo对象的属性进行绑定。既然这样,我们分别绑定复选框的value和title属性到Todo的isDone和title属性,以便某一方被更改时,另一方也自动更改。我们把它绑定起来:
in apps/todos/todos.js
// 在 SC.ready 之前
Todos.MarkDoneView = SC.Checkbox.extend({
titleBinding: ‘.parentView.content.title’,
valueBinding: ‘.parentView.content.isDone’
});
在我们提供的样式表中包含一个为已完成的代办事项提供独立样式的CSS class, 所以在你重新加载页面查看效果之前,先让我们也将每个项目的class与对象的isDone属性绑定起来。我们通过使用collection助手程序的一个属性来建立这个绑定。
in apps/todos/resources/templates/todos.handlebars
<!– 替换前面的代码 –>
{
{#collection SC.TemplateCollectionView ¬
contentBinding=”Todos.todoListController” ¬
itemClassBinding=”content.isDone”}}
{
{view Todos.MarkDoneView}}
{
{/collection}}
在每个项目视图上对这个属性进行绑定定义,如果项目对应的content对象的isDone属性是true,那它的class将是is-done。SproutCore会自动将属性名破折分隔化(注:原文dasherize,即以破折号分隔属性名,如isDone分隔成is-done)为class名。
所有视图都有很多属性,包括id,class以及classBinding。collection助手程序允许你在这些属性名前加上item字符,这样就会应用到子项目的视图。例如,如果在collection上使用itemClass属性,那么每个项目都会得到这个class。
现在在浏览器中重新加载应用程序,然后试一试。只要你一点击某个代办事项的复选框,那文字就会加上删除线。请牢记,当你标记Todo为已完成时,不需要你去更新任何视图,绑定会为你代劳。应用中任何一部分改变了Todo项目的isDone属性,代办列表会自动地更新,不需要你做任何工作。
8 你应该了解更多
现在我们可以创建代办事项,并且在完成时标记为已完成。然而76%的数据都是没用的,试想想我们是否能够从现有的数据中显示有用的信息。例如在列表的顶部,我们可以显示未完成的代办事项条数。
打开todos.handlebars,然后插入如下新视图:
in apps/todos/resources/templates/todos.handlebars
<!– 在 Todos.CreateTodoView 之后 –>
{
{#view Todos.StatsView id=”stats”}}
{
{displayRemaining}} remaining
{
{/view}}
当视图上的某个属性发生改变时,像{
{displayRemaining}} 这样的Handlebars表达式允许我们自动更新DOM。这种情况下,Todos.StatsView的content属性则应与视图的displayRemaining属性值进行绑定。跟其它的绑定一样,无论何时它的值改变时,它都会自动为我们更新。
我们现在接着继续在todos.js实现这个视图:
in apps/todos/todos.js
// 在 SC.ready 之前
Todos.StatsView = SC.TemplateView.extend({
remainingBinding: ‘Todos.todoListController.remaining’,
displayRemaining: function() {
var remaining = this.get(‘remaining’);
return remaining + (remaining === 1 ? ” item” : ” items”);
}.property(‘remaining’)
});
displayRemaining包含一个复数形式的字符串,根据剩余代办事项的条数而定。以上代码运行着SproutCore的另一个核心部分,一个称作计算属性(computed property)的概念。计算属性是指它的属性值是通过运行一个函数来决定的。例如,如果remaing等于1,则displayRemaining将是字符串”1 item”。
我们说displayRemaining依赖remaining,因为它需要另一个值去产生它自己的值。我们把这些依赖的键名在property()定义中列出来。
我们还对视图的remaining属性和todoListController的remaining属性进行了绑定,也就是说,如果Todos.todoListController.remaining发生了改变,那么displayRemaining也会自动被更新。
当我们需要在视图中显示与代办事项数据模型有关的信息时,最好是把它放到数组控制器中。现在让我们在todos.js文件的todoListController控制器中加入一个新的计算属性:
in apps/todos/todos.js
// 更新前面的代码
Todos.todoListController = SC.ArrayController.create({
// …
remaining: function() {
return this.filterProperty(‘isDone’, false).get(‘length’);
}.property(‘@each.isDone’)
});
这里,我们使用@each来指定属性的依赖关系,它让我们把属性依赖于数组的每个项目上。这样的话,当每条代办事项的isDone属性被改动时,remaining属性就会更新。
当一条代办事项被增加或删除时,@each属性也会更新。
定义计算属性的依赖属性非常重要,因为SproutCore依据它去知道何时更新绑定属性。既然这样,那么StatsView视图在todoListController控制器的remaining属性发生改变时就会更新。
让我们看看它们是如何结合在一起的:
在我们创建应用程序时,我们就声明了对象之间的链接关系,这些链接关系描述了应用的状态是如何从模型层流向HTML表现层的。
9 清理已完成的代办事项
除了在列表中填入代办事项,我们也希望可以定期清理那些已经完成的项目。正如你所学到的,我们将会在todoListController控制器中对它进行清理,并让SproutCore把这些操作所产生的变化自动地反映到DOM当中。
在控制器中增加一个新方法 clearCompletedTodos:
in apps/todos/todos.js
// 更新现有的代码
Todos.todoListController = SC.ArrayController.create({
// …
clearCompletedTodos: function() {
this.filterProperty(‘isDone’, true).forEach(this.removeObject, this);
}
});
接下来,打开todos.handlebars文件,在模板中增加一个按钮,如下面代码所示,在StatsView视图的HTML代码中插入:
in apps/todos/resources/templates/todos.handlebars
<!– 更新现有的代码 –>
{
{#view Todos.StatsView id=”stats”}}
{
{#view SC.Button classBinding=”isActive” ¬
target=”Todos.todoListController” ¬
action=”clearCompletedTodos”}}
Clear Completed Todos
{
{/view}}
{
{displayRemaining}} remaining.
{
{/view}}
我们已经定义了一个SC.Button实例,当它被点击时会调用某个对象的一个方法。在这里,我们让它在点击调用Todos.todoListController控制器(目标)对象的clearCompletedTodos方法(动作)。如果按钮已经被点击或轻敲一下(tapped),就让它在class属性中增加一个is-active类名,每个SC.Button按钮都有一个isActive属性,当按钮正在被点击时,它的值就为true。这样我们就可以向用户显示一个提醒效果,提示他们击中目标。
切换到浏览器,再刷新试试看。添加一些代办事项,然后把它们标记为已完成,然后再清理它们。因为我们先前就已经将可视列表与todoListController控制器进行了绑定,所以新加入的处理方式(即清理已完成代办事项)所产生的改变也同样得到预期的效果。
10 标记所有代办事项都已完成
我们试想下,假设你已经把代办事项中的所有工作都完成了,是否有好办法可以一次性的把所有代办事项都标记为已完成?
事实上,根据我们应用程序定义的性质,所有困难的工作都已经完成。我们只需要再增加一个标记所有代办事项为已完成的操作即可。
首先,在控制器中创建一个新的计算属性,用于标记是否所有的代办事项都已完成。它看起来像这样:
in apps/todos/todos.js
// 更新现有代码
Todos.todoListController = SC.ArrayController.create({
// …
allAreDone: function() {
return this.get(‘length’) && this.everyProperty(‘isDone’, true);
}.property(‘@each.isDone’)
});
SproutCore有许多枚举助手程序,如果数组中的对象有isDone属性且值为true,则everyProperty(‘isDone’,true)将返回true,否则返回false。你可以从Enumerables指南中找到更多相关信息。
接下来,我们创建一个复选框视图,用于标记所有代办事项为完成的状态,并将它的value属性与控制器的allAreDone属性进行绑定:
in apps/todos/resources/templates/todos.handlebars
<!– 直接在 Todos.StatsView 下面插入–>
{
{view SC.Checkbox class=”mark-all-done” ¬
title=”Mark All as Done” ¬
valueBinding=”Todos.todoListController.allAreDone”}}
如果你已经刷新浏览器并开始使用这个程序,你可能已经注意到,当你逐个将所有代办事项的复选框都勾选上后,“Mark All as Done”的复选框也变成已勾选状态。然而,它还不能反方向操作,即点击“Mark All as Done”时没有任何效果。
目前为止,我们的计算属性已经描述了如何从依赖属性中计算新的值。然而,在我们的程序中,我们想要接受一个新值,然后更新依赖的属性来反映这个值。让我们对allAreDone计算属性进行修改,让它也接受一个值。
in apps/todos/todos.js
// 更新现有代码
Todos.todoListController = SC.ArrayController.create({
// …
allAreDone: function(key, value) {
if (value !== undefined) {
this.setEach(‘isDone’, value);
return value;
} else {
return this.get(‘length’) && this.everyProperty(‘isDone’, true);
}
}.property(‘@each.isDone’)
});
当你设置一个计算属性时,计算属性函数会被调用,并会携带两个参数,第一个参数key就是属性键名,第二个参数value就是要设置的值。我们可以通过检查value的值是否已定义来判别到底是读属性操作,还是写属性操作。如果value有定义,就遍历代办事项并将它的isDone属性值设置为value的值。
由于绑定是双向的,当用户点击“Mark All as Done”复选框时,SproutCore会设allAreDone为true,相反,取消对“Mark All as Done”复选框的勾选时,SproutCore会设allAreDone为false,并取消对所有代办事项的勾选。
重新加载应用程序,再添加一些代办事项,然后点击“Mark All as Done”,哇!每个代办事项的复选框都被选上了。如果取消其中一个代办事项的勾选,那么“Mark All as Done”复选框就会取消选中。
你使用SproutCore时,当你扩展用户界面时,你从不需要怀疑是否新的特性将与现有的用户界面保持运作一致。因为你的视图层只是简单的反映模型的状态,你可以更改任何你想更改的东西,然后它们会自动更新。
11 移动设备特定样式
当前,所有当代的移动设备都具备运行我们这个程序的功能。我们需要为可能遇到的屏幕尺寸进行体验优化。下载CSS for mobile样式,然后保存到 apps/todos/resources/stylesheets/todos_mobile.css。然后在移动设备中访问这个应用程序,你会看到同样的应用,只是样式适当地根据移动设备进行调整,并且响应触摸事件。
你可以通过SproutCore开发服务器运行的机器的IP地址进行访问,如 http://192.168.1.1:4020/todos。
12 资源
你已经完成了入门教程的第一部分,你可以从社区中获得相关资源进行自学
- 加入 SproutCore邮件列表
- 在Twitter上关注 @sproutcore
- 访问 #sproutcore IRC 频道寻求实时帮助
- 把 SproutCore API Documentation 和 SproutCore Guides 加到收藏夹
13 继续
你已经创建了一个基本的SproutCore应用程序,继续进入本教程的下一部分,学习模型层的相关操作。
今天的文章SproutCore入门教程 – 第一部分分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/8277.html