简明 Vue.js 教程(3)

前面我们已经了解了有关 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#footertodolist的长度进行绑定,我们使用了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 项目有三种交互:

  1. 点击选择框,将其标记为完成状态,更新其completed属性值,并且要设置其父组件的 class 为completed
  2. 双击标签进入编辑模式,为其添加.editing
  3. 鼠标滑过是显示删除按钮(.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类。在过滤状态下,一个项目被修改,它应该同步更新。例如,如果过滤器是“活动的”而该项目被“完成”,那么它应该被隐藏。注意在每次加载时,持久化活动过滤器。

附件

Leave a Reply