TodoList製作

實現基本結構

  • 若下載好資料後可至 basic > todo.html 開始進行修改

  • 建立 資料陣列(todos) 與 暫時資料變數(newtodo)

<script>
    var app = new Vue({
        el: '#app',
        data: {
            newTodo: '',
            todos: [],
        },
        methods:{},
        computed:{}
    });
</script>
  • 在 input 使用 v-model 得到使用者輸入字串

  • 在 列表li 建立 v-for循環結構

實現增加資料

  • 增加 methods addTodo 用來增加資料

addTodo() {
    var value = this.newTodo.trim();
    var timestamp = Math.floor(Date.now());
    //如果沒有輸入則直接返回
    if (!value) {
        return;
    }
    this.todos.push({
        id: timestamp,
        title: value,
        completed: false                            
    });
    //將暫存區資料清除以便下次存取
    this.newTodo = '';
},
  • 將 addTodo 放入 button(@click="addTodo") 與 input( @keyup.enter) 方便加入列表資料

  • 將 放入label標籤內顯示資料名稱

  • 將 :for="item.id" 與 :id="item.id" 放入label 與 input 方便辨識各個資料

實現刪除資料

  • 在下面 button(x鍵) 加入 removeTodo 方法並傳入 item 指定刪除此資料

  • 建立 removeTodo 方法 來刪除列表資料

    • 傳入 item 並找出在todos對應的正確id

    • 利用找出的 id 刪除 item

removeTodo(todo) {
    let vm = this;
    let newIndex = vm.todos.findIndex(function(item){
        return todo.id === item.id;
    });
    this.todos.splice(newIndex,1);
},

實現刪除線

  • 增加 css

<style>
.completed {
    text-decoration: line-through;
}
</style>
  • 於input checkbox內增加 v-model="item.completed"(當按下時變為true)

  • 於label 增加 :class="{'completed':item.completed}" 來進行切換

實現過濾資料

  • 增加預設全部顯示 : 在 data 內新增 visibility='all'

  • 於連結增加 :class="{'active': visibility =='對應的參數'}" @click="visibility='對應的參數'"

<div class="card-header">
    <ul class="nav nav-tabs card-header-tabs">
        <li class="nav-item">
            <a class="nav-link " :class="{'active': visibility =='all'}" @click="visibility='all'" href="#">全部</a>
        </li>
        <li class="nav-item">
            <a class="nav-link " :class="{'active': visibility =='active'}" @click="visibility='active'" href="#">進行中</a>
        </li>
        <li class="nav-item">
            <a class="nav-link" :class="{'active': visibility =='completed'}" @click="visibility='completed'" href="#">已完成</a>
        </li>
    </ul>
</div>
  • 增加 computed 計算函數 : filteredTodos來回傳顯示的陣列資料

computed:{
    filteredTodos(){
        let newTodos = [];
        if(this.visibility == 'all'){
            return this.todos;
        }else if(this.visibility == 'active'){
            //對todos每一項資料進行循環檢測
            this.todos.forEach(function(item){
                if(!item.completed){
                    //將未完成資料放入新的陣列
                    newTodos.push(item);
                }
            })
            return newTodos;
        }else if(this.visibility == 'completed'){
            //對todos每一項資料進行循環檢測
            this.todos.forEach(function(item){
                if(item.completed){
                    //將未完成資料放入新的陣列
                    newTodos.push(item);
                }
            })
            return newTodos;
        }
    }
}
  • 將 v-for 的 todos 改成 filteredTodos 來顯示過濾後資料 即可進行過濾

實現雙擊修改標題功能

  • 新增預設變數 cacheTodo,cacheTile 存取更改資料

  • 新增修改函數 editTodo 存取使用者欲更改資料

editTodo(item){
    //用來儲存未更改資料
    this.cacheTodo = item;
    this.cacheTitle = item.title;
},
  • 在 li 新增雙擊事件 @dblclick="editTodo(item)

  • 新增 列表資料 與 input輸入框 互相切換顯示 : v-if="item.id !== cacheTodo.id" 與 v-if="item.id === cacheTodo.id"

  • 在 input 內增加 v-model="cacheTitle" 來讀取使用者修改資料

  • 在 input 內增加 esc離開編輯,enter完成編輯 事件

實現自動計算未完成筆數

  • 在 computed 新增 totall 函數

    totall(){
      let sum = this.todos.length;
      if(sum == 0){
          return sum;
      }else{
          this.todos.forEach(function(item){
              if(item.completed){
                  sum--;
              }
          })
          return sum;
      }                                
    }
  • {{totall}} 放入 <span> 之中即可

完成後程式碼

<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">
        <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 " :class="{'active': visibility =='all'}" @click="visibility='all'" href="#">全部</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link " :class="{'active': visibility =='active'}" @click="visibility='active'" href="#">進行中</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" :class="{'active': visibility =='completed'}" @click="visibility='completed'" href="#">已完成</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)">
                <div class="d-flex" v-if="item.id !== cacheTodo.id">
                    <div class="form-check">
                        <input type="checkbox" class="form-check-input" :id="item.id" v-model="item.completed">
                        <label class="form-check-label"
                        :class="{'completed':item.completed}" 
                        :for="item.id">
                            {{item.title}}
                        </label>
                    </div>
                    <button type="button" class="close ml-auto" aria-label="Close" @click="removeTodo(item)">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <input type="text" class="form-control" 
                v-model="cacheTitle"
                @keyup.esc="cancelEdit()"
                @blur="cancelEdit()"
                @keyup.enter="doneEdit(item)"
                v-if="item.id === cacheTodo.id">
            </li>
            <li class="list-group-item">
                <input type="text" class="form-control">
            </li>
        </ul>
        <div class="card-footer d-flex justify-content-between">
            <span>還有 {{totall}} 筆任務未完成</span>
            <a href="#" @click="removeAllItem()">清除所有任務</a>
        </div>
    </div>
</div>

<script>
    var app = new Vue({
        el: '#app',
        data: {
            newTodo: '',
            todos: [],
            visibility:'all',
            cacheTodo:{},
            cacheTitle:''
        },
        methods: {
            addTodo() {
                var value = this.newTodo.trim();
                var timestamp = Math.floor(Date.now());
                //如果沒有輸入則直接返回
                if (!value) {
                    return;
                }
                this.todos.push({
                    id: timestamp,
                    title: value,
                    completed: false                            
                });
                this.newTodo = '';
            },
            removeTodo(todo) {
                let vm = this;
                let newIndex = vm.todos.findIndex(function(item){
                    return todo.id === item.id;
                });
                this.todos.splice(newIndex,1);
            },
            editTodo(item){
                this.cacheTodo = item;
                this.cacheTitle = item.title;
            },
            cancelEdit(){
                this.cacheTodo = {};
            },
            doneEdit(item){
                item.title = this.cacheTitle;
                this.cacheTitle = '';
                this.cacheTodo = {};
            },
            removeAllItem(){
                this.todos = [];
                this.totall = 0;
            }
        },
        computed:{
            filteredTodos(){
                let newTodos = [];
                if(this.visibility == 'all'){
                    return this.todos;
                }else if(this.visibility == 'active'){
                    //對todos每一項資料進行循環檢測
                    this.todos.forEach(function(item){
                        if(!item.completed){
                            //將未完成資料放入新的陣列
                            newTodos.push(item);
                        }
                    })
                    return newTodos;
                }else if(this.visibility == 'completed'){
                    //對todos每一項資料進行循環檢測
                    this.todos.forEach(function(item){
                        if(item.completed){
                            //將未完成資料放入新的陣列
                            newTodos.push(item);
                        }
                    })
                    return newTodos;
                }
            },
            totall(){
                let sum = this.todos.length;
                if(sum == 0){
                    return sum;
                }else{
                    this.todos.forEach(function(item){
                        if(item.completed){
                            sum--;
                        }
                    })
                    return sum;
                }                                
            }
        }
    });
</script>

<style>
    .completed {
        text-decoration: line-through;
    }
</style>

Last updated