在瞭解了 Vue 的一些基本概念以後,就能夠寫一個最簡單的小項目了 --- TodoList。麻雀雖小,五張俱全。雖然是一個小 demo,但也涉及到了組件化、雙向綁定、自定義事件的觸發與監聽、計算屬性等概念。接下來從這個小項目中,對這些基本概念進行實踐,從而加深理解。html
本文的全部代碼在 https://github.com/nodejh/vue2-tutorials/tree/master/02.TodoList。vue
最終實現效果以下:node
接下來就一一實現。webpack
一樣使用 vue-cli
初始化項目,直接回車就行了。git
$ vue init webpack todoListDemo $ cd todoListDemo $ npm install $ npm run dev
啓動以後,瀏覽器就會自動現默認的頁面。github
在進行編碼以前,首先要考慮組件怎麼設計。在本文中,組件結構以下。web
+-----------------------+ | | | +-----------------+ | | | Todo Add | | | +-----------------+ | | +-----------------+ | | | | | | | Todo List | | | |+---------------+| | | || Todo Item || | | |+---------------+| | | |+---------------+| | | || Todo Item || | | |+---------------+| | | |+---------------+| | | || Todo Item || | | |+---------------+| | | | | | | +-----------------+ | | | +-----------------------+
其中主要包括兩個大的組件vue-router
TodoAdd
添加 Todo 的一個輸入框vue-cli
TodoList
Todo 列表,裏面有每個 Todo Itemshell
在 src/components
目錄下新建一個名爲 TodoList.vue
的文件,並添加以下代碼:
<template> <div id="todoList"> <h1>Todo List</h1> <ul class="todos"> <li v-for="todo, index in todos" class="todo"> <input type="checkbox" name="" value="" :checked="todo.isCompleted" > <span :class="todo.isCompleted ? 'completed' : ''" @ > <em>{{ index + 1 }}.</em>{{ todo.text }} </span> </li> </ul> </div> </template> <script> export default { name: 'TodoList', data: () => ({ todos: [{ text: '吃飯', isCompleted: false }, { text: '睡覺', isCompleted: false }] }) } </script> <style scoped> #todoList { margin: 0 auto; max-width: 350px; } .todos li { list-style: none; } .todo { text-align: left; cursor: pointer; } .completed { text-decoration: line-through; } </style>
在 TodoList
中,使用 todos
數組來保存全部的 todo list。其中每個 todo 都是對象,對象裏面有兩個屬性,分別是 todo 的內容,和 todo 是否完成的標誌。默認給數組添加了兩個 todo,主要用於演示。
src/components/Hello.vue
在本項目中沒什麼用,能夠隨意刪除。
而後修改 src/router/index.js
:
import Vue from 'vue' import Router from 'vue-router' import TodoList from '@/components/TodoList' Vue.use(Router) export default new Router({ routes: [ { path: '/', name: 'todoList', component: TodoList } ] })
修改完以後,vue 會自動從新編譯並刷新頁面,這時瀏覽器的頁面以下:
在該 demo 中,當點擊 todo item 或者前面的複選框的時候,就完成 todo。因此如今須要添加完成 todo 的方法,並設置 todo item 的點擊事件。
像下面這樣修改 src/components/TodoList.vue
中的 template
部分:
<input type="checkbox" name="" value="" :checked="todo.isCompleted" @click="completed(index)" > <span :class="todo.isCompleted ? 'completed' : ''" @click="completed(index)" > <em>{{ index }}.</em>{{ todo.text }} </span>
而後在組件裏面添加對應的 completed
方法:
<script> export default { // 其餘現有代碼 name: 'TodoList', methods: { completed(index) { this.todos[index].isCompleted = !this.todos[index].isCompleted } } } </script>
當點擊 check box
或 span
的時候,就調用 completed
方法並傳入被點擊的 todo item 的索引。在 completed
方法裏面,更新數據對象 data 裏面對應的 todo item 的 isCompleted
屬性。這樣就實現了完成 todo 和取消完成 todo 的功能。點擊以後如圖:
接下來就須要完成添加新的 todo 的功能了。
新建一個文件 src/components/TodoAdd.vue
,添加以下代碼:
<template> <div id="addTodo"> <input type="text" name="" class="input" value="" v-model="todo" @keyup.enter="addTodo" > <button type="button" name="button" @click="addTodo" > 添加 </button> </div> </template> <script> export default { name: 'addTodo', data: () => ({ todo: '' }), methods: { addTodo () { if (this.todo) { this.$emit('add', this.todo) this.todo = '' } else { alert('內容不能爲空') } } } } </script> <style scoped> .input { min-width: 200px; } </style>
首先在組件的數據對象 data
裏面有一個 todo
屬性,用來存儲用戶輸入的內容。而後在 template
的 input
輸入框裏,使用 v-model
實現雙向綁定。
當用戶按下回車(@keyup.enter="addTodo"
,詳見 鍵值修飾符)或者點擊添加按鈕(@click="addTodo"
)的時候,就調用 methods
裏面的 addTodo
方法。
addTodo
方法經過 vm.$emit
觸發了一個 add
事件,並將用戶輸入的內容(即 this.todo
)做爲參數傳遞。事件觸發以後,將輸入框中的內容清空。
接下來就須要監聽 add
事件了。監聽事件須要在使用組件的模板裏面,經過 v-on
來實現。詳見 使用-v-on-綁定自定義事件。
在 src/components/TodoList.vue
中使用 AddTodo
這個子組件:
<h1>Todo List</h1> <!-- 調用子組件,並使用 v-on 監聽 add 方法 --> <!-- 當 add 事件觸發時,就調用當前組件 addTodo 這個方法 --> <todo-add v-on:add="addTodo"></todo-add> <ul class="todos"> <!-- // 調用子組件 --> <script> // 引入子組件 import TodoAdd from './TodoAdd.vue' export default { name: 'TodoList', components: { TodoAdd }, // ... methods: { // ... // 添加新的 todo addTodo() { this.todos.push({ text: todo, isCompleted: false }) } } } </script>
到此,添加 todo 和完成 todo 功能就實現了。
接下來還能夠作點別的事情,好比顯示總共的 todo 數目,以及完成和未完成的數目。
要實現此功能,方法有不少種。最簡單的一種是直接在模板中加入 JS 表達式,來顯示總共的數目,好比:
<p>總共有 <strong>{{ this.todos.lengt }}</strong> 個待辦事項。</p>
對於簡單的邏輯能夠很方便用表達式寫出來,但若是是比較複雜的邏輯,好比統計未完成數目(固然這個也能夠用一個表達式搞定),可能一個表達式看起來就不太清晰。這個時候就能夠用計算屬性。
修改 src/components/TodoList.vue
:
<!-- // ... --> <ul class="todos"> <!-- // ... --> </ul> <div> <p v-show="todos.length === 0"> 恭喜!全部的事情都已完成! </p> <p v-show="todos.length !== 0"> 共 <strong>{{ todos.length }}</strong> 個待辦事項。{{ completedCounts }} 個已完成,{{ notCompletedCounts }} 個未完成。 </p> </div> <script> // ... export default { name: 'TodoList', // ... computed: { completedCounts () { return this.todos.filter(item => item.isCompleted).length }, notCompletedCounts () { return this.todos.filter(item => !item.isCompleted).length } } } </script>
上述代碼中經過 completedCounts
和 notCompletedCounts
兩個計算屬性,來計算出已完成和未完成的 todo。雖然這兩個表達式能夠直接放在模板中,但表達式比較複雜,看起來也不是很清晰,因此不少時候就能夠用計算屬性來計算出一個最終值,而後在模板中使用。
到此,基於 Vue 的 Todo List 就完成了。在該項目中,對組件化、雙向綁定、自定義事件的觸發與監聽、計算屬性等概念進行了實踐。固然,最重要的不是完成這個 Todo List 的代碼,而是從實現功能的過程當中觸類旁通,經過簡單的 demo 實現,去思考如何用 vue 開發一個更大更完整的項目。