iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 14
0
Modern Web

實作小範例入門 Vue & Vuex 2.0系列 第 14

vue & vuex 14 - 經典 todo list - II (改變狀態與 delete)

今天目標:

  1. 希望標示已經完成的待辦事項
  2. 希望未完成事項與完成的事項分開存放
  3. 事項越來越多,希望有刪除功能

getter.js

首先我會從 getter 下手,分開撈取: 未完成 / 完成

export const getDone = state => {
  return state.todos.filter((item) => {
    return item.done;
  });
}
export const getTodo = state => {
  return state.todos.filter((item)=>{
    return !item.done;
  });
}

修改為兩隻 getter 因 getter 不能傳值 (可以傳請告訴我..)

使用 filter 過濾 item.done

分開撈取: 未完成 / 完成


todo.vue

<template>
  <div class="container">
    <h1>vue & vuex Todo List example</h1>
    <hr>
    <div class="row">
      <div class="input-group col-md-4">
        <input
          type="text"
          class="form-control"
          placeholder="add Todo.."
          v-model="newTodo"
          @keyup.enter="actionAddTodo" />
        <span class="input-group-btn">
          <button class="btn btn-success" type="button" @click="actionAddTodo">
            <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
          </button>
        </span>
      </div>
    </div>
    <!-- 左右兩個欄位分別存放 todo / done -->
    <div class="row">
      <div class="col-md-6">
        <h2>Todo List:</h2>
        <li v-for="(item, index) in todoList">
          <label>
            <!-- 
              改變狀態
              套用 vuex 因此不能使用 v-model 做雙向綁定,會報錯誤
              1. 將 list 的 value bind 到 input checked 屬性上,改變樣式。
              2. onchange 事件發出 action 帶入 key
             -->
            <input 
              type="checkbox"
              :checked="item.done"
              @change="toggleTodo( item.key )">
              {{ item.content }}
          </label>
          <!-- 
			刪除按鈕 
			onclick 事件發出 action 帶入 key
		  -->
          <button class="btn btn-xs btn-danger" @click="deleteTodo( item.key )">
            <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
          </button>
        </li>
      </div>
      <div class="col-md-6">
        <h2>Done List:</h2>
        <ul >
          <li v-for="(item, index) in doneList">
            <label>
              <input 
                type="checkbox"
                :checked="item.done"
                @change="toggleTodo( item.key )">
                {{ item.content }}
            </label>
          </li>
        </ul>
      </div>
    </div><!-- end row -->
  </div>
</template>

<script>
import { mapGetters, mapActions } from 'vuex'

export default {
  data () {
    return {
      newTodo: ''
    }
  },
  computed: mapGetters({
    todoList: 'getTodo',
    doneList: 'getDone',
  }),
  methods: {
    ...mapActions([
        'toggleTodo',
        'deleteTodo',
    ]),
    actionAddTodo () {
      this.$store.dispatch('addTodo', this.newTodo);
      this.newTodo = '';
    }
  }
}
</script>

到這便順利完成,分開兩張表顯示。


action.js

export const toggleTodo = ({ commit }, key) => {
  commit(types.TOGGLE_TODO, key);
}

export const deleteTodo = ({ commit }, key) => {
  commit(types.DELETE_TODO, key);
}

action 目前都還很單純只把 key 帶給 metution


metutions.js

// 改變狀態
[types.TOGGLE_TODO] (state, key) {
  for(var i in state.todos){
    var item = state.todos[i];
    if ( item.key === key){
      item.done = !item.done;
      console.log('TOGGLE_TODO:', item.content, 'done?', item.done);
      break;
    }
  }
},
// 刪除
[types.DELETE_TODO] (state, key) {
  for(var i in state.todos){
    var item = state.todos[i];
    if ( item.key === key){
      console.log('DELETE_TODO:', item.content, ', index?', i);
      state.todos.splice(i, 1);
      break
    }
  }
},

改變狀態:

這邊用比較簡單的 for 迴圈,將傳進來的 key 找到 todo, 把狀態反向,更新 state。

刪除:

一樣是找到 todo 後單純將 todo Array 從 splice 出去。

UI 怎麼會變化?

state 更新的時候 gatter 就會撈取新的狀態,反映到 Vue 上面。

掌握 vuex 了嗎? 邏輯寫在 metution 因為只有它可以改變 state
state 改變 gatter 會更新 Vue 完成數據驅動
你只需要操縱 JSON !


github 完整範例:

實作小範例入門 Vue & Vuex 2.0 - github 完整範例

使用 git checkout 切換每天範例。


上一篇
vue & vuex 13 - 經典 todo list - I (create, read)
下一篇
vue & vuex 15 - 經典 todo list - III (update)
系列文
實作小範例入門 Vue & Vuex 2.030
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
0
garrodran99
iT邦新手 5 級 ‧ 2017-10-20 20:04:37

我的Delete 和 Toggle 是這樣, 進行了簡化

  [types.DELELTE_TODO] (state, key) {
    var index = state.todos.findIndex(item => item.key === key)
    state.todos.splice(index, 1)
    console.log(`TODOS DELETED. key: ${key}, index: ${index}`)
  },
  [types.TOGGLE_TODO] (state, key) {
    var item = state.todos.find(item => item.key === key)
    item.done = !item.done
    console.log('TOGGLE_TODO: ', item.content, 'done?', item.done)
  }

getter 也做了些簡化:

export const getTodos = state => state.todos.filter(item => !item.done)

export const getDoneTodos = state => state.todos.filter(item => item.done)
Jacky iT邦新手 5 級 ‧ 2017-10-20 22:20:09 檢舉

hi garrodran99,

當初在寫這篇的時候,想法是直觀的表現 function 在做什麼,所以故意用最簡單的寫法很醜很蠢那種,目的就是不要讓大家一眼看不出來在做什麼,或者要在去看 ES6 語法或者 array 操作語法這樣。

我覺得這樣的學習是很跳躍的,主要是當初在公司內部介紹的時候發現這樣的情況,如果我寫這些語法讓程式變美變簡潔,反而讓第一次看的人跳脫了 vuex 的流程 介紹這個主軸,跑去注意 ES6 語法,或者有種學 vuex 就要學 ES6 的感覺(當然一定要)但是我要先讓他們先喜歡、暸解、覺得 vuex 流程可以解決目前開發上遇到的困難這樣(然後再推坑 ES6 這樣)。

非常感謝你在留言中,正確的示範套用 ES6 語法可以多麽的省略,簡潔,直觀的開發。

0
garrodran99
iT邦新手 5 級 ‧ 2017-10-20 20:07:50

還有想問下, this.newTodo = ''; 這個放在組件裡面直接修改, 是不是不太好?
newTodo 我覺得也要放進去 mutation 裡面修改, 因為 addTodo 不保證一定成功, 應該等成功後才清空的.

0
garrodran99
iT邦新手 5 級 ‧ 2017-10-22 23:15:25

改變狀態
套用 vuex 因此不能使用 v-model 做雙向綁定,會報錯誤
1. 將 list 的 value bind 到 input checked 屬性上,改變樣式。
2. onchange 事件發出 action 帶入 key

我把
:checked="item.done"
@change="toggleTodo( item.key )">
刪掉, 直接改成 v-model="item.done" , 完全沒有任何問題啊. toggle 那個 method 也沒有用了.

但想了想, 應該不容許這種直接修改, 我再研究一下

我要留言

立即登入留言