vue-todolist
功能列表
-
input輸入文字按回車新增事項
-
雙擊事項顯示編輯輸入框,按Enter鍵或失去焦點確認修改,按ESC鍵取消修改
-
點選x刪除事項
-
點選勾選切換事項狀態,未完成/已完成
-
全選/反選
-
切換all、active、completed顯示對應的事項
-
儲存資料到localstorage
結構樣式
使用vue改寫
-
引入vue.js
-
建立vue例項
let vm = new Vue({
el: '.todoapp',
data: {
list: [],
title: '',
editTodoIndex: -1,
beforeTitle: ''
},
methods: {
addTodo(){},
removeTodo(){},
editTodo(){},
editDone(){},
editCancel(){}
}
});
複製程式碼
- 渲染資料
<ul class="todo-list" ref="todoList">
//事項有3種狀態
//1.未完成沒有class
//2.已完成有class completed
//3.編輯狀態有class editing
<li
v-for="(item,index) in list"
:class="{completed: item.checked,editing: index === editTodoIndex}"
>
<div class="view">
<input
class="toggle"
type="checkbox"
v-model="item.checked"
/>
<label @dblclick="editTodo(index)">{{item.title}}</label>
<button
class="destroy"
@click="removeTodo(item)"
></button>
</div>
<input
class="edit"
v-model='item.title'
@blur="editDone(item)"
@keyup.13="editDone(item)"
@keyup.esc="editCancel(item)"
/>
</li>
</ul>
複製程式碼
- 新增功能
<input class="new-todo" placeholder="請輸入內容" @keyup.13 = 'addTodo' v-model='title' />
addTodo(){
if(this.title.trim() === '') return;
this.list.push({
title: this.title,
id: Date.now(),
checked: false
});
this.title = '';
}
複製程式碼
- 刪除功能
removeTodo(todo){
let index = this.list.findIndex(item => item === todo);
this.list.splice(index,1)
}
複製程式碼
- 編輯功能
//新增ref
<input
ref='edit'
class="edit"
v-model='item.title'
@blur="editDone(item)"
@keyup.13="editDone(item)"
@keyup.esc="editCancel(item)"
/>
editTodo(index){
this.editTodoIndex = index;
//編輯的時候顯示修改輸入框,使用refs獲取dom設定焦點
this.$nextTick( () => {
this.$refs.edit[index].focus()
})
// 編輯時候儲存一下title
this.beforeTitle = this.list[index].title;
}
複製程式碼
editDone(todo){
//當title為空刪除
if(!todo.title.trim()){
this.removeTodo(todo);
}
this.editTodoIndex = -1;
this.beforeTitle = '';
}
複製程式碼
editCancel(todo) {
this.editTodoIndex = -1;
todo.title = this.beforeTitle;
}
複製程式碼
- 全選功能
<input class="toggle-all" v-model='isCheckedAll' type="checkbox" />
computed: {
isCheckedAll: {
get(){
return this.list.length ? this.list.every(item => item.checked) : false
},
set(newValue){
this.list.forEach(item => item.checked = newValue)
}
}
}
複製程式碼
- 計算未選中多少條
<footer class="footer">
<span class="todo-count">
<strong>{{uncheckedLen}}</strong>
<span>條未選中</span>
</span>
...
</footer>
computed: {
...
uncheckedLen(){
return this.list.filter(item => !item.checked).length;
}
}
複製程式碼
- 當todolist為空不顯示footer
<footer class="footer" v-show="list.length">
...
</footer>
複製程式碼
- todo型別切換
let filterActive = {
all(list){
return list
},
active(list){
return list.filter(item => !item.checked)
},
completed(list){
return list.filter(item => item.checked)
}
}
// 當hash值改變時觸發的事件
window.onhashchange = function (){
let hashVal = window.location.hash;
if(hashVal){
hashVal = hashVal.slice(2);
hashVal = filterActive[hashVal] ? hashVal : 'all'
}else{
hashVal = 'all';
}
// 改變例項下的過濾條件
vm.hash = hashVal;
}
window.onhashchange();
複製程式碼
//過濾todolist
computed: {
isCheckedAll: {
get(){
return this.filterList.length ? this.filterList.every(item => item.checked) : false
},
set(newValue){
this.filterList.forEach(item => item.checked = newValue)
}
},
uncheckedLen(){
return this.filterList.filter(item => !item.checked).length;
},
filterList(){
return filterActive[this.hash](this.list);
}
}
複製程式碼
//修改渲染列表
<li
:class="{completed: item.checked,editing: index === editTodoIndex}"
v-for="(item,index) in filterList"
>
//新增hash
data: {
...
hash: 'all'
}
//判斷hash值新增selected樣式
<footer class="footer" v-show="list.length">
...
<ul class="filters">
<li><a href="#/all" :class="{selected:hash === 'all'}">All</a></li>
<li><a href="#/active" :class="{selected:hash === 'active'}">Active</a></li>
<li><a href="#/completed" :class="{selected:hash === 'completed'}">Completed</a></li>
</ul>
</footer>
複製程式碼
- 把資料儲存到localstorage
//新增修改刪除修改資料都需要儲存,所以使用watch深度監控list變化然後儲存
watch: {
list:{
handler(){
localStorage.setItem('todoListData', JSON.stringify(this.list));
},
deep:true
}
}
複製程式碼
//獲取資料
let data = JSON.parse(localStorage.getItem('todoListData')) || [];
let vm = new Vue({
...
data: {
...
list: data
}
})
複製程式碼
完整示例