實現一個 TodoList - Vue2 Tutorials (二)

本文同步於 Github nodejh/vue2-tutorials

在了解了 Vue 的一些基本概念之後,就可以寫一個最簡單的小項目了 --- TodoList。麻雀雖小,五張俱全。雖然是一個小 demo,但也涉及到了組件化、雙向綁定、自定義事件的觸發與監聽、計算屬性等概念。接下來從這個小項目中,對這些基本概念進行實踐,從而加深理解。

本文的所有代碼在 nodejh/vue2-tutorials。

最終實現效果如下:

接下來就一一實現。

nodejh/vue2-tutorials初始化項目

同樣使用 vue-cli 初始化項目,直接回車就好了。

$ vue init webpack todoListDemon$ cd todoListDemon$ npm installn$ npm run devn

啟動之後,瀏覽器就會自動現默認的頁面。

在進行編碼之前,首先要考慮組件怎麼設計。在本文中,組件結構如下。

+-----------------------+n| |n| +-----------------+ |n| | Todo Add | |n| +-----------------+ |n| +-----------------+ |n| | | |n| | Todo List | |n| |+---------------+| |n| || Todo Item || |n| |+---------------+| |n| |+---------------+| |n| || Todo Item || |n| |+---------------+| |n| |+---------------+| |n| || Todo Item || |n| |+---------------+| |n| | | |n| +-----------------+ |n| |n+-----------------------+n

其中主要包括兩個大的組件

  • TodoAdd 添加 Todo 的一個輸入框
  • TodoList Todo 列表,裡面有每一個 Todo Item

添加 TodoList 組件

在 src/components 目錄下新建一個名為 TodoList.vue 的文件,並添加如下代碼:

<template>n <div id="todoList">n <h1>Todo List</h1>n <ul class="todos">n <li v-for="todo, index in todos" class="todo">n <inputn type="checkbox"n name=""n value=""n :checked="todo.isCompleted"n >n <spann :class="todo.isCompleted ? completed : "n @n >n <em>{{ index + 1 }}.</em>{{ todo.text }}n </span>n </li>n </ul>n </div>n</template>n<script>nexport default {n name: TodoList,n data: () => ({n todos: [{n text: 吃飯,n isCompleted: falsen }, {n text: 睡覺,n isCompleted: falsen }]n })n}n</script>n<style scoped>n#todoList {n margin: 0 auto;n max-width: 350px;n}n.todos li {n list-style: none;n}n.todo {n text-align: left;n cursor: pointer;n}n.completed {n text-decoration: line-through;n}n</style>n

在 TodoList 中,使用 todos 數組來保存所有的 todo list。其中每一個 todo 都是對象,對象裡面有兩個屬性,分別是 todo 的內容,和 todo 是否完成的標誌。默認給數組添加了兩個 todo,主要用於演示。

src/components/Hello.vue 在本項目中沒什麼用,可以隨意刪除。

然後修改 src/router/index.js:

import Vue from vuenimport Router from vue-routernimport TodoList from @/components/TodoListnnVue.use(Router)nnexport default new Router({n routes: [n {n path: /,n name: todoList,n component: TodoListn }n ]n})n

修改完之後,vue 會自動重新編譯並刷新頁面,這時瀏覽器的頁面如下:

添加完成 Todo 的方法

在該 demo 中,當點擊 todo item 或者前面的複選框的時候,就完成 todo。所以現在需要添加完成 todo 的方法,並設置 todo item 的點擊事件。

像下面這樣修改 src/components/TodoList.vue 中的 template 部分:

<inputn type="checkbox"n name=""n value=""n :checked="todo.isCompleted"n @click="completed(index)"n>n<spann :class="todo.isCompleted ? completed : "n @click="completed(index)"n>n <em>{{ index }}.</em>{{ todo.text }}n</span>n

然後在組件裡面添加對應的 completed 方法:

<script>nexport default {n // 其他現有代碼n name: TodoList,n methods: {n completed(index) {n this.todos[index].isCompleted = !this.todos[index].isCompletedn }n }n}n</script>n

當點擊 check box 或 span 的時候,就調用 completed 方法並傳入被點擊的 todo item 的索引。在 completed 方法裡面,更新數據對象 data 裡面對應的 todo item 的 isCompleted 屬性。這樣就實現了完成 todo 和取消完成 todo 的功能。點擊之後如圖:

TodoAdd 組件

接下來就需要完成添加新的 todo 的功能了。

新建一個文件 src/components/TodoAdd.vue,添加如下代碼:

<template>n <div id="addTodo">n <inputn type="text"n name=""n class="input"n value=""n v-model="todo"n @keyup.enter="addTodo"n >n <buttonn type="button"n name="button"n @click="addTodo"n >n 添加n </button>n </div>n</template>n<script>nexport default {n name: addTodo,n data: () => ({n todo: n }),n methods: {n addTodo () {n if (this.todo) {n this.$emit(add, this.todo)n this.todo = n } else {n alert(內容不能為空)n }n }n }n}n</script>n<style scoped>n.input {n min-width: 200px;n}n</style>n

首先在組件的數據對象 data 裡面有一個 todo 屬性,用來存儲用戶輸入的內容。然後在 template 的 input 輸入框里,使用 v-model 實現雙向綁定。

當用戶按下回車(@keyup.enter="addTodo",詳見 鍵值修飾符)或者點擊添加按鈕(@click="addTodo")的時候,就調用 methods 裡面的 addTodo 方法。

addTodo 方法通過 vm.$emit 觸發了一個 add 事件,並將用戶輸入的內容(即 this.todo)作為參數傳遞。事件觸發之後,將輸入框中的內容清空。

接下來就需要監聽 add 事件了。監聽事件需要在使用組件的模板裡面,通過 v-on 來實現。詳見 使用-v-on-綁定自定義事件。

nodejh/vue2-tutorials完成添加 Todo 功能

在 src/components/TodoList.vue 中使用 AddTodo 這個子組件:

<h1>Todo List</h1>n<!-- 調用子組件,並使用 v-on 監聽 add 方法 -->n<!-- 當 add 事件觸發時,就調用當前組件 addTodo 這個方法 -->n<todo-add v-on:add="addTodo"></todo-add>n<ul class="todos">n<!-- // 調用子組件 -->nn<script>n // 引入子組件n import TodoAdd from ./TodoAdd.vuen export default {n name: TodoList,n components: {n TodoAddn },n // ...n methods: {n // ...n // 添加新的 todon addTodo() {n this.todos.push({n text: todo,n isCompleted: falsen })n }n }n }n</script>n

到此,添加 todo 和完成 todo 功能就實現了。

nodejh/vue2-tutorialsTodo 統計

接下來還可以做點別的事情,比如顯示總共的 todo 數目,以及完成和未完成的數目。

要實現此功能,方法有很多種。最簡單的一種是直接在模板中加入 JS 表達式,來顯示總共的數目,比如:

<p>總共有 <strong>{{ this.todos.lengt }}</strong> 個待辦事項。</p>n

對於簡單的邏輯可以很方便用表達式寫出來,但如果是比較複雜的邏輯,比如統計未完成數目(當然這個也可以用一個表達式搞定),可能一個表達式看起來就不太清晰。這個時候就可以用計算屬性。

修改 src/components/TodoList.vue:

<!-- // ... -->n<ul class="todos">n<!-- // ... -->n</ul>n<div>n <p v-show="todos.length === 0">n 恭喜!所有的事情都已完成!n </p>n <p v-show="todos.length !== 0">n 共 <strong>{{ todos.length }}</strong> 個待辦事項。{{ completedCounts }} 個已完成,{{ notCompletedCounts }} 個未完成。n </p>n</div>nnn<script>n// ...nexport default {n name: TodoList,n // ...n computed: {n completedCounts () {n return this.todos.filter(item => item.isCompleted).lengthn },n notCompletedCounts () {n return this.todos.filter(item => !item.isCompleted).lengthn }n }n}n</script>n

上述代碼中通過 completedCounts 和 notCompletedCounts 兩個計算屬性,來計算出已完成和未完成的 todo。雖然這兩個表達式可以直接放在模板中,但表達式比較複雜,看起來也不是很清晰,所以很多時候就可以用計算屬性來計算出一個最終值,然後在模板中使用。

nodejh/vue2-tutorials總結

到此,基於 Vue 的 Todo List 就完成了。在該項目中,對組件化、雙向綁定、自定義事件的觸發與監聽、計算屬性等概念進行了實踐。當然,最重要的不是完成這個 Todo List 的代碼,而是從實現功能的過程中舉一反三,通過簡單的 demo 實現,去思考如何用 vue 開發一個更大更完整的項目。


推薦閱讀:

現在做 Web 全景合適嗎?
掘金日報】第四期 使用Sublime?怎麼能不知道這些 Sublime 插件合集!
web前端如何才算入門?如何才算合格?如何才算大牛?
不可或缺的柯里化

TAG:Vuejs | 前端开发 |