之前的實作練習都沒有機會使用到 Vuex,總是覺得它的資料存取、取得或是管理,對於剛接觸Vue 的我來說還是相對複雜,而且剛開始接觸 Vue 總要先練習下 props \ emit 資料傳遞才行啊~
既然已經會使用基礎的資料傳遞後,那就要近一步實作 Vuex 狀態管理
實作功能說明
- 資料的取得來自 JSONPlaceholder
- 從Vuex來實作資料的取得、刪除、更新
- 針對目前取得的資料進行筆數的篩選
- 區分未完成事項、以及完成事項
- 可透過點擊方塊改變色塊
- 接下來~會製作 3個 component ,將元件放到 App.vue
開始前別忘了先建立 module
Vuex 檔案的處理
- 這裡開專案直接有建立 vuex
- 進入 store > index.js
1 | import { createStore } from 'vuex'; |
建立 modules 資料夾
- store > modules > todo.js
- 取得假資料
jsonplaceholder-todo在 todo.js 來製作資料的串接
- 首先state這裡要先建立空陣列,getters 則是建立資料取得的函式
- 在action 來發出請求,取得回應,並傳給 mutations
- mutations 是改變資料的地方
- 引入axios,使用 Asyc await 使用 get 來串接資料
- 將串到的資料 commit 到 mutations,改變原本todos資料內容
1 | import axios from 'axios'; |
建立 Todos.vue
此元件主要是呈現所有的 Todo list
取得 vuex 中的資料
引入 mapGetters, mapActions
將要從 getters 拿到的陣列,放到computed做資料的取得
- 將該陣列
getTodos
放到 v-for
- 將該陣列
串接的 action 使用 mapActions,於 methods中執行,而此函式要在
created
階段運行如此一來就可以,從 Vuex 中得到資料
1 | <template> |
製作加入新 todo 功能
- 建立一個新的 component => AddTodo.vue
- 在 AddTodo 這個元件,製作 輸入框
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<template>
<div>
<h3>Add Todo</h3>
<div class="add">
<form>
<input type="text" placeholder="Add Todo..." v-model="title" />
<input type="submit" value="Submit" />
</form>
</div>
</div>
</template>
<script>
export default {
name: "AddTodo",
};
</script>到 module > todo.js
- 使用 async 與 axios 傳入資料
- 第二個參數為 title
- post 的網址一樣,後面接的參數為title, complete: false (any new todo that it’s not going to completed)
1 | const actions = { |
- 而在action 中使用axios 來新增資料,要將這必新資料 push 到 todo的陣列中
- 存入的該資料要放在,陣列的最前面所以使用 unshift
1
2
3
4
5
6
7
8const mutations = {
setTodos: (state, todos) => {
state.todos = todos;
},
addNewTodo: (state, todo) => {
state.todos.unshift(todo);
}
};
- 存入的該資料要放在,陣列的最前面所以使用 unshift
到 AddTodo.vue 來呼叫此 action
- import
mapActions
1 | <template> |
1 |
|
這裡要特別提出說明
因為是使用線上的虛擬資料,他不允許我們可以存入新資料到他的API裡面
所以可以看到下方的錯誤顯示(重複 id)
而此在重新整理之後,存入的資料會消失
製作刪除功能
- 以id作為參數,來依此刪除
- 不用儲存response資料
- 在 async deleteTodo ,製作 by id 刪除
- 到 mutations => 使用 filter 存下資料
1 | import axios from 'axios'; |
- 回到 Todos.vue
- 在 template 放入垃圾桶的 icon
- 執行刪除的功能,在 icon 綁定刪除事件
deleteTodo()
deleteTodo()
就是來自於 methods 取得的事件1
2
3
4
5
6
7
8
9<template>
<h3>Todos</h3>
<div class="todos">
<div class="todo" v-for="todo in getTodos" :key="todo.id">
{{ todo.title }}
<i class="fas fa-trash-alt" @click="deleteTodo(todo.id)"></i>
</div>
</div>
</template>1
2
3
4
5
6
7
8
9
10
11
12
13
14<script>
import { mapGetters, mapActions } from "vuex";
export default {
name: "Todos",
methods: {
...mapActions(["fetchTodos", "deleteTodo"]),
},
computed: mapGetters(["getTodos"]),
created() {
this.fetchTodos();
},
};
</script>
- 執行刪除的功能,在 icon 綁定刪除事件
製作篩選器功能
- 當 FilterTodo.vue 這裡的篩選器執行的時候,會執行 action中的函式,進行篩選
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<style scoped>
select {
margin-top: 20px;
padding: 6px;
border: #ef9a9a 1px solid;
}
</style>
<template>
<div>
Filter todos:
<select>
<option value="200">200</option>
<option value="100">100</option>
<option value="50">50</option>
<option value="30">30</option>
<option value="20">20</option>
<option value="10">10</option>
</select>
</div>
</template>1
2
3
4
5<script>
export default {
name: "FilterTodos",
};
</script>
將該元件綁到 App.vue
1 | <template> |
到 module > todo.js 來製作 actions
- 要傳入 option 的 value
- 第二個參數為事件
- 在 axios 的 get 放入 url,接上取得的參數
- commit 直接傳到 setTodos ,將串接到的資料透過 mutations 存到 todos
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39import axios from 'axios';
const state = {
todos: []
};
const getters = {
getTodos: (state) => state.todos,
};
const actions = {
async filterTodos({ commit }, e) {
//取得下拉選單的值
//console.log(e.target.value);
let selected = parseInt(e.target.value);
const res = await axios.get(`https://jsonplaceholder.typicode.com/todos?_limit=${selected}`);
commit('setTodos', res.data);
}
};
const mutations = {
setTodos: (state, todos) => {
state.todos = todos;
},
addNewTodo: (state, todo) => {
state.todos.unshift(todo);
},
removeTodo: (state, id) => {
state.todos = state.todos.filter((todo) => todo.id !== id);
//使用filter 將,不是id的篩選出來
}
};
export default {
state,
getters,
actions,
mutations
}
- 將action 綁到 FilterTodos.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template>
<div>
Filter todos:
<select @change="filterTodos($event)">
<option value="200">200</option>
<option value="100">100</option>
<option value="50">50</option>
<option value="30">30</option>
<option value="20">20</option>
<option value="10">10</option>
</select>
</div>
</template>
<script>
import { mapActions } from "vuex";
export default {
name: "FilterTodos",
methods: {
...mapActions(["filterTodos"]),
},
};
</script>
todos 完成與否,狀態的改變
- 點擊兩下來更改狀態
- 當要更新資料,要使用put,傳入updTodo物件資料
- 將該資料傳到mutation
- 接著到 mutation 製作更新的動作
- 要取得目前的index
- 當要更新資料,要使用put,傳入updTodo物件資料
1 | import axios from 'axios'; |
回到 Todos.vue
- template 插入legend
- 引入
updataTodo
到 methods onDblclick()
建立一個變數,它包含的物件內容為id、title、completed,其中我只要要改變的值是 complete true\false- 這裡的 id,title 都一樣。complete 則設定狀態的改變
- 最後在呼叫一次
updataTodo()
傳入新的物件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<template>
<h3>Todos</h3>
<div class="legend">
<span>雙重點擊來標示已完成的事項</span>
<span> <span class="incomplete-box"></span> = 未完成 </span>
<span> <span class="complete-box"></span> = 已完成 </span>
</div>
<div class="todos">
<div
@dblclick="onDblclick(todo)"
class="todo"
v-for="todo in getTodos"
:key="todo.id"
:class="{ 'is-complete': todo.completed }"
>
{{ todo.title }}
<i class="fas fa-trash-alt" @click="deleteTodo(todo.id)"></i>
</div>
</div>
</template>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<script>
import { mapGetters, mapActions } from "vuex";
export default {
name: "Todos",
methods: {
...mapActions(["fetchTodos", "deleteTodo", "updataTodo"]),
onDblclick(todo) {
const updTodo = {
id: todo.id,
title: todo.title,
completed: !todo.completed,
};
this.updataTodo(updTodo);
},
},
computed: mapGetters(["getTodos"]),
created() {
this.fetchTodos();
},
};
</script>
參考資料:
[Vue.js] Vuex 學習筆記 (5) - getters 的核心概念
Vuex
Using this.$store.dispatch
vs using mapActions