iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 28
0
Modern Web

For 前端小幼苗的圖解筆記系列 第 28

[Vue.js + Axios] ToDoList (上)

鐵人賽終於來到最後兩篇(最後一天是廢文心得文)

這兩天來個大顆ㄧ點(跟前幾篇比)的栗子,用 Vue.js 實作一個「一眼瞬間」版的 ToDoList。
為什麼叫「一眼瞬間」呢?因為 F5 刷新就沒啦! 先來做這個最基本連 localStorage 都沒有的 ToDoList,當做 Vue.js 應用練習。
但怕被認為這樣太混,再多加一項初始載入指定的 API(Axios GET)。


練習素材:


先來將該做的事情列成清單:

  1. (data)資料格式定義,每筆待辦項有:'id' / 'title' / 'completed'

    • id 值不可重複
    • completed 為 true / false
  2. 可以讀取(R)初始資料(API GET)

  3. 可以新增(C)待辦項並即時顯示(預設狀態為「未完成」)

  4. 可以編輯(U)目前的待辦項

    • 更名
    • 點擊時變更完成狀態
  5. 可以刪除(D)待辦項

  6. 可以一次刪除所有待辦項

  7. 頁籤(Tab)依完成狀態分類清單:全部 / 進行中 / 已完成

  8. 計數目前未完成的項,且有變動時即時更新計數


查看完整栗子 >> Codepen Demo


(下列 HTML 的部分這邊只截取有應用到 Vue.js 的部分,也就是要觸發事件 / 進行資料綁定的,完整版請看 Codepen)



<div class="container" id="app">
  <input class="form-control" type="text" placeholder="準備要做的任務" 
          v-model="newTodo" @keyup.enter="addTodo"/>
  <div class="input-group-append">
    <button class="btn" type="button" @click="addTodo">新增</button>
    <template v-for="(item, index) in visibilityList">
      <li class="nav-item" :key="index"></li>
      <a class="nav-link" href="#" :class="{ active: visibility == item.value }" 
          @click="(visibility = item.value)">{{ item.name }}
      </a>
    </template>
    <template v-for="(item) in filteredTodos">
      <li class="list-group-item" :key="item.id" @dblclick="editTodo(item)">
        <div v-if="item.id !== cacheTodo.id">
          <input class="form-check-input" :id="item.id" type="checkbox" 
                  @click="changeComplated(item.id)" 
                  v-model="item.completed"/>
          <label class="form-check-label" :class="{ completed: item.completed }"
                  :for="item.id"> {{ item.title }}
          </label>
          <button class="close" type="button" aria-label="Close" 
                  @click="removeTodo(item)">×
          </button>
        </div>
        <input class="form-control" type="text" 
            v-model="cacheTitle" v-if="item.id == cacheTodo.id" 
            @keyup.esc="cancelEdit" @keyup.enter="doneEdit(item)"/>
      </li>
    </template>
  </div>
  <div class="card-footer">
      {{ `還有${activeTodosLength}筆任務未完成` }}
      <a href="#" @click="cleanTodo">清除所有任務</a>
  </div>
</div>
var urlAPI = "https://eudora-hsj.github.io/Vue-practice/data/todolist.json"

var app = new Vue({
    el: "#app",
    data() {
        return {
            newTodo:'',
            todos: [],
            visibilityList: [
                { name: "全部", value: "all" },
                { name: "進行中", value: "active" },
                { name: "已完成", value: "completed" }
            ],
            visibility: 'all',
            cacheTodo: {},
            cacheTitle: '',
        }
    },
    created() {
        this.getList(urlAPI)
    },
    methods: {
        getList(url) {
            axios
                .get(url)
                .then((res) => {
                    this.todos = res.data.data
                })
                .catch((err) => {
                    console.log(err)
                })
        },
        addTodo() {
            let newTodoStr = this.newTodo.trim()
            if (!newTodoStr) {
                return
            }
            this.newTodo = ""
            let submitData = {
                id: Math.floor(Date.now()),
                title: newTodoStr,
                completed: false
            }
            this.todos.push(submitData)
        },
        removeTodo(item) {
            this.todos.splice(this.getIndex(item.id), 1)
        },
        editTodo(item) {
            this.cacheTodo = item
            this.cacheTitle = item.title
        },
        cancelEdit() {
            this.cacheTodo = {}
        },
        doneEdit(item) {
            item.title = this.cacheTitle
            this.cacheTitle = ""
            this.cacheTodo = {}
        },
        cleanTodo() {
            this.todos.splice(0, this.todos.length)
        },

        getIndex(id) {
            return this.todos.findIndex((el) => el.id == id)
        },
        changeComplated(id){
            let index = this.getIndex(id)
            this.todos[index].completed = !this.todos[index].completed
        }
    },
    computed: {
        filteredTodos() {
            let nowTab = this.visibility
            switch (nowTab) {
                case "all":
                    return this.todos.filter((item) => true)
                case "active":
                    return this.todos.filter((item) => !item.completed)
                case "completed":
                    return this.todos.filter((item) => item.completed)
            }
        },
        getNewKey() {
            return Math.max(...this.todos.map((el) => +el.id))
        },
        activeTodosLength() {
            return this.todos.filter((item) => !item.completed).length
        }
    }
})

程式碼說明:

~ 待下篇繼續囉!


個人 Blog: https://eudora.cc/


上一篇
[Vue.js] 基本語法
下一篇
[Vue.js + Axios] ToDoList (下)
系列文
For 前端小幼苗的圖解筆記30

尚未有邦友留言

立即登入留言