前面我们已经了解了有关 Vue.js 的基础知识,本章我们开始创建一个经典的 todo 程序。我们选择 todomvc 作为页面模板。虽然 Vue.js 官方已经提供了类似的示例,但是现在,我们自己在 todomvc 模板基础上,自己使用 Vue.js 实现相关功能。
todomvc 原始模板可以在 github 下载;具体实现要求则可以在这里找到。首先我们使用 git clone 下来模板。todomvc 使用 npm 管理依赖。npm 是 nodejs 的包管理工具,类似于 Java 的 maven 之类。安装好 nodejs 后,就可以直接使用 npm。进入到 close 下来的 todomvc-app-template 文件夹,运行 npm install 命令即可。如果你不想安装 nodejs,本文末尾有完整的模板打包文件,提供给初学者使用。
准备好模板文件之后,在浏览器打开 todomvc-app-template 中的 index.html,可以看到运行界面(点击这里运行)。
这只是一个静态模板,没有任何动态的功能。我们的目标,就是按照todomvc应用规范,使用 Vue.js 实现这些需求。
todomvc 的需求比较简单:页面上有一个输入框,每次输入内容,按下回车将新增一行;用户也可以选择删除一行,或者双击编辑等。因此我们的思路是,维护一个 todolist 数组,将视图与这个数组进行绑定。这一点看起来与之前我们写的代码非常类似,事实也的确如此。
按照todomvc应用规范,我们自己的 JavaScript 代码必须写在 js/app.js 中。于是,我们修改这个文件如下:
(function (window) {
'use strict';
// Your starting point. Enjoy the ride!
new Vue({
el: '.todoapp',
data: {
todolist: []
}
});
})(window);
查看 index.html 页面,整个应用位于>section class="todoapp"<中,因此Vue对象的el属性设置为.todoapp。目前我们只需要一个data,即todolist数组。同时,todomvc应用规范要求,当todolist为空时,#main和#footer应该隐藏。所以,我们修改 index.html 页面相关代码如下:
...
<section class="todoapp">
<!-- This section should be hidden by default and shown when there are todos -->
<section class="main" v-show="todolist.length">
...
</section>
<!-- This footer should hidden by default and shown when there are todos -->
<footer class="footer" v-show="todolist.length">
...
</footer>
</section>
... 为了将#main和#footer与todolist的长度进行绑定,我们使用了v-show指令。v-show指令控制被绑定的元素是否要显示。我们将其绑定到todolist.length,由于todolist.length默认值为 0,JavaScript 认为是false,因此不会显示#main和#footer。当我们给todolist添加元素之后,todolist.length不为 0,#main和#footer将会显示。到目前为止还挺顺利的!
todomvc应用规范要求,使用页面上方的输入框创建新的 todo。页面加载完毕后,该输入框需要自动获得焦点;当输入完毕按下回车键,新增一个 todo 项目,同时清空输入框。输入的内容需要首先使用trim()函数过滤掉两侧空白字符。
这对我们来说基本不是问题,因为在前面的章节,我们已经完成了类似的工作,只需要简单地重新添加一下就可以了。至于页面加载完毕自动获取焦点,只需要给<input>标签添加autofocus属性即可——这是 HTML5 新增属性,正是为了达到类似的目的。
为了新增 todo,我们需要为我们的模型增加一个newTodo数据,其类型暂时只需是字符串:
new Vue({
el: '.todoapp',
data: {
todolist: [],
newTodo: ''
},
methods: {
addTodo: function () {
if (this.newTodo) {
var todo = this.newTodo.trim();
this.todolist.push(todo);
this.newTodo = '';
}
}
}
}); 然后修改 HTML 中的.header和.main两部分如下:
<header class="header">
<h1>todos</h1>
<input class="new-todo" placeholder="What needs to be done?" autofocus v-model="newTodo" @keyup.enter="addTodo">
</header>
<!-- This section should be hidden by default and shown when there are todos -->
<section class="main" v-show="todolist.length">
<input class="toggle-all" type="checkbox">
<label for="toggle-all">Mark all as complete</label>
<ul class="todo-list">
<!-- These are here just to show the structure of the list items -->
<!-- List items should get the class `editing` when editing and `completed` when marked as completed -->
<li v-for="todo in todolist">
<div class="view">
<input class="toggle" type="checkbox">
<label>{{todo}}</label>
<button class="destroy"></button>
</div>
<input class="edit" value="Rule the web">
</li>
</ul>
</section> 首先,我们在<input>标签添加了v-model属性,将<input>绑定到数据模型newTodo;然后为<input>添加了键盘事件@keyup.enter,用于监听回车事件。这部分代码与之前的示例非常相似,这里不再赘述。
这部分代码的执行点击这里运行。
最后再按照todomvc应用规范对比下我们实现了什么:
没有 todo 时
没有 todo 的时候,#main和#footer应当隐藏。
新增 todo
在应用上方的输入框按下回车新增 todo。当页面加载完毕后,输入框应该获得焦点,这可以使用autofocus属性实现。按下回车创建 todo,将其追加到 todo 列表最后,同时清空输入框。确保对输入值调用.trim(),并且在创建新 todo 之前检查是否为空。
标记所有为完成
该checkbox将所有 todo 设置为与自己相同的状态。在点击“Clear completed”按钮之后清空所选状态。当一个 todo 项目被选择或反选是,“Mark all as complete”应该同步更新。例如,当所有 todo 都被勾选时,它也应该是选择状态。
项目
一个 todo 项目有三种交互:
- 点击选择框,将其标记为完成状态,更新其
completed属性值,并且要设置其父组件的 class 为completed - 双击标签进入编辑模式,为其添加
.editing类 - 鼠标滑过是显示删除按钮(
.destroy)
编辑
进入编辑模式时,其它组件将被隐藏,只显示包含 todo 标题的输入框,这个输入框应该获得焦点(.focus())。失去焦点或者按下回车结束编辑,移除.editing类。确保对输入值调用.trim(),并且在创建新 todo 之前检查是否为空。如果为空,该 todo 应该被销毁。如果在编辑时点击了Esc,应该退出编辑状态,丢弃所有修改。
计数器
以复数形式显示活动的 todo 数。该数值需要使用<strong>标签。并且要保证复数形式是正确的:0 items,1 item,2 items。例如,2 items left
Clear completed 按钮
点击按钮移除已完成 todo。如果没有已完成 todo,隐藏该按钮。
持久化
应用应该能够将 todo 动态持久化到 localStorage。如果框架自身能够处理持久化数据(例如 Backbone.sync),使用框架提供的即可。否则,使用 vanilla localStorage。如果可能的话,为每个 todo 定义 id、title、completed。localStorage 使用如下名称格式:todos-[framework]。编辑模式不应该被持久化。
路由
所有实现都需要路由。如果框架支持路由,使用内置的路由机制。否则,使用 /assets 文件夹中的 Flatiron Director 路由库。需要实现下列路由:#/ (全部 - 默认);#/active 和 #/completed (也可以使用 #!/)。路由变化时,todu 列表应该在模型级别进行过滤,过滤器链接应该添加selected类。在过滤状态下,一个项目被修改,它应该同步更新。例如,如果过滤器是“活动的”而该项目被“完成”,那么它应该被隐藏。注意在每次加载时,持久化活动过滤器。
附件