Let's VUE[3]

webdq發表於2018-05-03

vue-todolist

功能列表

  • input輸入文字按回車新增事項

  • 雙擊事項顯示編輯輸入框,按Enter鍵或失去焦點確認修改,按ESC鍵取消修改

  • 點選x刪除事項

  • 點選勾選切換事項狀態,未完成/已完成

  • 全選/反選

  • 切換all、active、completed顯示對應的事項

  • 儲存資料到localstorage

結構樣式

使用vue改寫

  1. 引入vue.js

  2. 建立vue例項

let vm = new Vue({
  el: '.todoapp',
  data: {
    list: [],
    title: '',
    editTodoIndex: -1,
    beforeTitle: ''
  },
  methods: {
    addTodo(){},
    removeTodo(){},
    editTodo(){},
    editDone(){},
    editCancel(){}
  }
});
複製程式碼
  1. 渲染資料
<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>
複製程式碼
  1. 新增功能
<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 = '';
}
複製程式碼
  1. 刪除功能
removeTodo(todo){
  let index = this.list.findIndex(item => item === todo);
  this.list.splice(index,1)
}
複製程式碼
  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;
}
複製程式碼
  1. 全選功能
<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)
    }
  }
}
複製程式碼
  1. 計算未選中多少條
<footer class="footer">
  <span class="todo-count">
    <strong>{{uncheckedLen}}</strong>
    <span>條未選中</span>
  </span>
  ...
</footer>

computed: {
  ...
  uncheckedLen(){
    return this.list.filter(item => !item.checked).length;
  }
}
複製程式碼
  1. 當todolist為空不顯示footer
<footer class="footer" v-show="list.length">
...
</footer>
複製程式碼
  1. 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>
複製程式碼
  1. 把資料儲存到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
  }
})
複製程式碼

完整示例

點選這裡檢視完整示例

相關文章