# [Vue.js] Todolist實作程式碼
###### tags: `Vue.js`
1. 輸入字串後,跳至列表
2. 勾選checkbox後,文字出現刪除線
3. 切換頁籤
4. 雙點擊修改(跳出+完成修改)
5. 刪除列表(一般+進階)
```
<!DOCTYPE html>
<html>
<head>
<title>Todo 範例製作</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="images/favicon.ico" rel="shortcut icon">
<meta charset="UTF-8">
<link rel="stylesheet" href="/stylesheets/all.css">
<script defer src="https://use.fontawesome.com/releases/v5.0.8/js/solid.js" integrity="sha384-+Ga2s7YBbhOD6nie0DzrZpJes+b2K1xkpKxTFFcx59QmVPaSA8c7pycsNaFwUK6l" crossorigin="anonymous"></script>
<script defer src="https://use.fontawesome.com/releases/v5.0.8/js/regular.js" integrity="sha384-t7yHmUlwFrLxHXNLstawVRBMeSLcXTbQ5hsd0ifzwGtN7ZF7RZ8ppM7Ldinuoiif" crossorigin="anonymous"></script>
<script defer src="https://use.fontawesome.com/releases/v5.0.8/js/fontawesome.js" integrity="sha384-7ox8Q2yzO/uWircfojVuCQOZl+ZZBg2D2J5nkpLqzH1HY0C1dHlTKIbpRz/LG23c" crossorigin="anonymous"></script> <script src="/javascripts/vendor.js"></script>
</head>
<body class="bg-lighter">
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<a class="navbar-brand" href="/">Vue.js 練習手冊</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarText">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="/basic/dev.html">基礎教學</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/template/basic.html">模板指令</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/components/basic.html">組件</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/api/vue_set.html">常用 API</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/es6/let_const.html">ES6</a>
</li>
</ul>
</div>
</nav>
<div class="container my-5">
<div class="row">
<div class="col-md-3">
<div>
<h6 class="text-capitalize text-muted">basic</h6>
<a href="/basic/dev.html" class="btn btn-block btn-link">
Vue 的開發環境
</a>
<a href="/basic/instant.html" class="btn btn-block btn-link">
建立 Vue 的應用程式
</a>
<a href="/basic/mvvm.html" class="btn btn-block btn-link">
MVVM 是什麼樣的概念
</a>
<a href="/basic/directive.html" class="btn btn-block btn-link">
指令
</a>
<a href="/basic/if_for.html" class="btn btn-block btn-link">
模板語法的延伸 v-if 及 v-for
</a>
<a href="/basic/v_on.html" class="btn btn-block btn-link">
處理互動式行為 v-on 指令
</a>
<a href="/basic/defined_var.html" class="btn btn-block btn-link">
預先定義資料結構
</a>
<a href="/basic/modifiers.html" class="btn btn-block btn-link">
修飾符 與 縮寫
</a>
<a href="/basic/v_class.html" class="btn btn-block btn-link">
切換 Class
</a>
<a href="/basic/computed.html" class="btn btn-block btn-link">
計算屬性
</a>
<a href="/basic/form.html" class="btn btn-block btn-link">
表單雙向綁定
</a>
<a href="/basic/components.html" class="btn btn-block btn-link">
元件化
</a>
<a href="/basic/todo.html" class="btn btn-block btn-primary active">
Todo 範例練習
</a>
<a href="/basic/v_lifecycle.html" class="btn btn-block btn-link">
延伸介紹 - Vue 生命週期
</a>
</div>
</div>
<div class="col-md-9 post">
<!-- 練習開始 -->
<h1 class="mt-0 text-muted">Todo 範例製作</h1>
<div class="alert alert-secondary">
<ol class="mb-0">
<li>請跟隨課程完成此章節。</li>
</ol>
</div>
<div id="app">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">待辦事項</span>
</div>
<!-- 輸入代辦事項 -->
<input type="text" class="form-control" placeholder="準備要做的任務" v-model="newTodo" @keyup.enter="addTodo"> <!-- 點選enter鍵便會傳入至list裡,需放置在input填表欄的位置,而非bottom鍵 -->
<div class="input-group-append">
<!-- 新增按鈕 -->
<button class="btn btn-primary" type="button" @click="addTodo">新增</button>
</div>
</div>
<div class="card text-center">
<div class="card-header">
<!-- 三頁籤區塊 -->
<ul class="nav nav-tabs card-header-tabs">
<li class="nav-item">
<a class="nav-link " href="#" :class="{'active':visibility == 'all'}" @click="visibility ='all'">全部</a> <!-- :class語法{觸發:條件} ,點擊頁籤all之後傳至:class裡並觸發active -->
</li>
<li class="nav-item">
<a class="nav-link " href="#" :class="{'active':visibility == 'active'}" @click="visibility ='active'" >進行中</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" :class="{'active':visibility == 'completed'}" @click="visibility ='completed'" >已完成</a>
</li>
</ul>
</div>
<ul class="list-group list-group-flush text-left">
<!-- 顯示及編輯代辦內容 -->
<li class="list-group-item" v-for="(item,key) in filteredTodos" @dblclick="editTodo(item)"> <!-- item後方加上索引key,可方便程式判定是哪一筆要刪除 -->
<div class="d-flex" v-if="item.id !== cacheTodo.id"> <!-- 如果id不同觸發的動作,片點是5:30分鐘-->
<div class="form-check">
<input type="checkbox" class="form-check-input" v-model="item.completed" :id="item.id">
<label class="form-check-label"
:class="{'completed': item.completed}"
:for="item.id"> <!-- :class部分是將文字畫刪除線功能,:for是input中的id與label的for對應,點擊“checkbox”光標就會定位到input輸入框 -->
{{item.title}}
</label>
</div>
<!-- 刪除按鈕 -->
<button type="button" class="close ml-auto" aria-label="Close" @click="removeTodo(item)" > <!-- 刪除資料,標記key -->
<span aria-hidden="true">×</span>
</button>
</div>
<!-- 更改編輯欄位的事件 -->
<!-- 下方的v-model使得修改字串時,原字串內容能顯示在編輯欄上 -->
<input type="text" class="form-control"
v-if="item.id === cacheTodo.id"
@keyup.esc="cancelEdit"
v-model="cacheTitle"
@keyup.enter="doneEdit(item)"
>
</li>
</ul>
<div class="card-footer d-flex justify-content-between">
<span>還有 3 筆任務未完成</span>
<a href="#">清除所有任務</a>
</div>
</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
newTodo:'',
todos:[{
id:'0204',
title:'',
completed: false,
}],
cacheTodo:{},
cacheTitle:'',
visibility:'all'
},
methods:{
addTodo: function(){
var value = this.newTodo.trim(); //需新增變數來宣告在data裡的資料 //新增trim可消除空白位置
var timestamp = Math.floor(Date.now()); //產生亂數,將時間轉換成數字
if(!value){ //無法新增空白內容
return; //如果value是空值,會回傳nothing不會啟動功能
}
this.todos.push({ //將新增的物件傳至todos陣列裡
id:timestamp,
title:value,
completed:false,
})
this.newTodo = ''; // 將欄位恢復成空值
},
// remove的第一種寫法
//下方的todo及item及key都是可自定義的變數
removeTodo: function(todo){ //todo代表目前所點選的物件
var newIndex ='';
this.todos.forEach(function(item,key){ // 這裡的key是另一個變數當比對轉換使用
if(todo.id === item.id){ //todo指的是當下點擊的物件id,item是todos裡頭的物件id
newIndex = key
}
})
this.todos.splice(newIndex , 1)
},
// removeTodo: function(todo){
// var newIndex = this.todos.findIndex(function(item,key){
// return todo.id === item.id;
// })
// this.todos.splice(newIndex , 1)
// },
editTodo :function(item){ //核心重點,雙點擊後的動作
console.log(item)
this.cacheTodo = item; //將item結果導入data的存取區域
this.cacheTitle = item.title;
},
cancelEdit:function(){
this.cacheTodo ={} //將cacheTodo的陣列變成空物件
},
doneEdit:function(item){ //取消編輯功能,產生空物件的狀態
item.title = this.cacheTitle; //將item.title裡的值導入cacheTitle裡
this.cacheTitle ='';
this.cacheTodo ={} //??回傳數據
},
},
computed:{
filteredTodos:function(){ //新增一個函式命名
if(this.visibility == 'all'){ //當visibility顯示all回傳todos
return this.todos;
}else if(this.visibility == 'active'){ //重點部分,剩兩個部分用判斷式(completed的布林值)來區分
var newTodos=[]; //新陣列
this.todos.forEach(function(item){ //forEach函式執行每個陣列內的物件或值,取用原先todos
if(!item.completed){
newTodos.push(item); //符合條件的輸入至新的陣列newTodos裡
}
})
return newTodos;
}
else if(this.visibility == 'completed'){
var newTodos=[];
this.todos.forEach(function(item){ //forEach()一個由原陣列中的每個元素呼叫一個指定方法後的返回值組成的新陣列
if(item.completed){
newTodos.push(item);
}
})
return newTodos; //回傳至newTodos後會顯示在todos,因使用forEach綁定this.todos
}
return[];
}
}
});
//第一章
//建立data間的屬性,並在html裡的各個功能區段新增v-model等連結
//並新增methods導入觸發事件@click=""
//功能一:輸入的事項在點選新增後,顯示於下方lable,A:增加新物件並使用push新增
//第二章
//功能二:避免空值(if語法))以及空白鍵(trim語法))會新增語法
//功能三:刪除陣列資料,在函數內使用splice語法刪除事項,著重於與html的索引key串連
//第三章
//功能四:點選checkbox後會在陣列文字顯示刪除線,A:使用:class語法將style內容與completed的布林值串接
//功能五:“高級語法”製作頁籤分類功能 A:html上新增@click語法對應三個頁籤,並使用computed函數做判斷式宣告,一般做判斷是都適用
//補充:!item.completed使用判斷式,可直譯if(item.completed)就等於ture,則{結果},相對應的!item.completed等於false
//跳脫一定要使用既有的屬性,創立一個新的函數後,點選all的部分回傳既有全部todos內容,其他兩個使用判斷式來區別顯示資料
//先增加新命名,並新增新的[]陣列以判定“未完成”“完成”的item事項,採用forEach迴圈
//第四章
//功能六:雙點擊修改資料內容,list欄位放上雙點擊觸發事件
//在data新增有暫存功能的cache title與todo,並綁定method裡的函數
//新增判斷式,在雙點擊A後1. 因為cache與item的id吻合,因此會彈出修改窗,2.而我們再雙擊另一個item B,則A因不吻合id而關閉顯本來的字串內容,而B因id吻合則開啟
//按鍵esc以及enter存入編輯內容,enter按鈕點擊時,將item的內容title載入存取的cache
//第五章
//功能七:刪除項目補充,可以在'進行中''已完成'使用刪除功能
</script>
<style>
.completed {
text-decoration: line-through
}
</style>
</div>
</div>
</div>
</body>
</html>
```
# todolist操作步驟
1. 輸入字串後,跳至列表
2. 勾選checkbox後,文字出現刪除線
3. 切換頁籤
4. 雙點擊修改(跳出+完成修改)
5. 刪除列表(一般+進階)
目的:在lable上輸入的字串,因點擊觸發而傳入新的陣列裡,顯示在頁面中
1. lable上使用v-model能同步顯示此輸入的數值
2. data裡新創一個A陣列(裡頭是初始值)
3. 點擊事件觸發後,需規劃一個大工程,建立函數method,將data裡的陣列連結新增的變數裡,包含title(data裡的newTodo)及id隨機數
4. 再者宣告一個物件(放入新的id、title、布林值) this.todos.push意指將methods裡的新陣列傳入舊的todos裡(data裡的A陣列)
5. !!!重要:push的目的基本上就是要將輸入的newTodo導入todos陣列裡,需多宣告一個變數value再導入todos陣列裡,也就是輸入的值能顯示在list中,中間需要再宣告一個新變數做連結,過程繁複需記住。
6. 記憶小技巧
* 小技巧,將輸入的字串在按下botton後消失,需要在外圍宣告一個空字串
* 小技巧,輸入字串如有空格會自動省略,需要使用trim
* 小技巧,無輸入字串將無法觸發,需增加一個判斷式,如(!value)則無回傳,!!!重點:!value意指value沒有值
7. 頁籤切換的語法
第一步驟:
宣告一個空字串A
使用:class來啟動對應的頁籤,如:class{'active':字串狀態}
@click觸發空字串A的狀態,並再傳至:class裡以啟動active效果將頁籤切換至指定頁面上
第二步驟:
//跳脫要使用既有的屬性,創立一個新的函數後,點選all的部分回傳既有全部todos內容,其他兩個使用判斷式來區別顯示資料
//先新增新陣列[],以判定“未完成”“完成”的item事項,採用forEach迴圈
8. 雙點擊修改項目文字
第一步驟:
data新增兩個變數([],''),在@dblclick函式將原item變數與新變數串連
用v-if判定點擊後,當id相同時便會跳出input視窗,如果不同就會在原視窗
enter後修改陣列的文字內容,將新titile輸入進原先的字串中,並記得用空陣列
小技巧:按esc後跳出,可使用空陣列
小技巧:使用v-model綁定,可在修改中原文字出現在表框中
9. 勾選checkbox出現刪除線
checkbox功能裡的input的id必須要與label的for綁定
並使用:class('刪除效果':completed)
10. 刪除線
第一個方法可採用key索引(item,key) in list
再使用splice公式刪除第一個項目
第二個方法綁定id來刪除,重要的是代入參數(這邊的參數都是自定義)
使用forEach迴圈,並做if判斷當id是相同的便會刪除