Skip to content

Commit 3f76cb0

Browse files
committed
Vuex tutorial - simple todos example
1 parent 610f8ea commit 3f76cb0

File tree

9 files changed

+174
-66
lines changed

9 files changed

+174
-66
lines changed

package-lock.json

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
},
1010
"dependencies": {
1111
"core-js": "^2.6.5",
12-
"vue": "^2.6.10"
12+
"vue": "^2.6.10",
13+
"vuex": "^3.1.1"
1314
},
1415
"devDependencies": {
1516
"@vue/cli-plugin-babel": "^3.12.0",

src/App.vue

+20-7
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,37 @@
11
<template>
22
<div id="app">
3-
<img alt="Vue logo" src="./assets/logo.png">
4-
<HelloWorld msg="Welcome to Your Vue.js App"/>
3+
<h1>Todos</h1>
4+
<h3>Completed: {{ completedTodos }}</h3>
5+
<h3>Pending: {{ pendingTodos }}</h3>
6+
<todos-list />
7+
<todo-form />
58
</div>
69
</template>
710

811
<script>
9-
import HelloWorld from './components/HelloWorld.vue'
12+
import { mapGetters } from "vuex";
13+
import TodosList from "./components/TodosList";
14+
import TodoForm from "./components/TodoForm";
1015
1116
export default {
12-
name: 'app',
17+
name: "app",
1318
components: {
14-
HelloWorld
19+
TodosList,
20+
TodoForm
21+
},
22+
23+
computed: {
24+
...mapGetters({
25+
completedTodos: "completedTodos",
26+
pendingTodos: "pendingTodos"
27+
})
1528
}
16-
}
29+
};
1730
</script>
1831

1932
<style>
2033
#app {
21-
font-family: 'Avenir', Helvetica, Arial, sans-serif;
34+
font-family: "Avenir", Helvetica, Arial, sans-serif;
2235
-webkit-font-smoothing: antialiased;
2336
-moz-osx-font-smoothing: grayscale;
2437
text-align: center;

src/components/HelloWorld.vue

-58
This file was deleted.

src/components/Todo.vue

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<template>
2+
<div style="width:250px; margin:5px auto;">
3+
<div style="display:flex; justify-content:space-between">
4+
<span :class="{completed: todo.completed}" @click="toggleTodoStatus(todo)">{{ todo.title }}</span>
5+
<button @click="removeTodo(todo)">Delete</button>
6+
</div>
7+
</div>
8+
</template>
9+
10+
<script>
11+
import { mapActions } from "vuex";
12+
export default {
13+
props: ["todo"],
14+
15+
methods: {
16+
...mapActions({
17+
removeTodo: "deleteTodo",
18+
toggleTodoStatus: "toggleTodoStatus"
19+
})
20+
}
21+
};
22+
</script>
23+
24+
<style scoped>
25+
.completed {
26+
text-decoration: line-through;
27+
}
28+
</style>

src/components/TodoForm.vue

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<template>
2+
<div>
3+
<input type="text" v-model="newTodoItem" />
4+
<button @click="addNewTodoItem()">Submit</button>
5+
</div>
6+
</template>
7+
8+
<script>
9+
export default {
10+
data() {
11+
return {
12+
newTodoItem: ""
13+
};
14+
},
15+
16+
methods: {
17+
addNewTodoItem() {
18+
this.$store.dispatch("addNewTodo", this.newTodoItem);
19+
this.newTodoItem = "";
20+
}
21+
}
22+
};
23+
</script>
24+
25+
<style>
26+
</style>

src/components/TodosList.vue

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<template>
2+
<div>
3+
<todo v-for="(todo, index) in todos" :key="index" :todo="todo" />
4+
</div>
5+
</template>
6+
7+
<script>
8+
import { mapState } from "vuex";
9+
import Todo from "./Todo";
10+
11+
export default {
12+
components: {
13+
Todo
14+
},
15+
16+
computed: {
17+
...mapState({
18+
todos: "todos"
19+
})
20+
}
21+
};
22+
</script>
23+
24+
<style>
25+
</style>

src/main.js

+3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import Vue from 'vue'
22
import App from './App.vue'
3+
import store from "./store";
4+
35

46
Vue.config.productionTip = false
57

68
new Vue({
9+
store,
710
render: h => h(App),
811
}).$mount('#app')

src/store.js

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import Vue from "vue";
2+
import Vuex from 'vuex';
3+
4+
Vue.use(Vuex);
5+
6+
export default new Vuex.Store({
7+
state: {
8+
todos: [
9+
{
10+
title: "todo item a",
11+
completed: false
12+
},
13+
{
14+
title: "todo item b",
15+
completed: false
16+
},
17+
]
18+
},
19+
20+
getters: {
21+
completedTodos(state) {
22+
return state.todos.filter(todo => {
23+
return todo.completed === true;
24+
}).length;
25+
},
26+
27+
pendingTodos(state) {
28+
return state.todos.filter(todo => {
29+
return todo.completed === false;
30+
}).length;
31+
}
32+
},
33+
34+
mutations: {
35+
NEW_TODO(state, todoItem) {
36+
state.todos.push({
37+
title: todoItem,
38+
completed: false
39+
})
40+
},
41+
42+
DELETE_TODO(state, todoItem) {
43+
let index = state.todos.indexOf(todoItem);
44+
state.todos.splice(index, 1);
45+
},
46+
47+
TOGGLE_TODO_STATUS(state, todoItem) {
48+
todoItem.completed = !todoItem.completed;
49+
}
50+
},
51+
52+
actions: {
53+
addNewTodo({ commit }, todoItem) {
54+
commit('NEW_TODO', todoItem);
55+
},
56+
57+
deleteTodo({ commit }, todoItem) {
58+
commit('DELETE_TODO', todoItem);
59+
},
60+
61+
toggleTodoStatus({ commit }, todoItem) {
62+
commit('TOGGLE_TODO_STATUS', todoItem);
63+
}
64+
}
65+
});

0 commit comments

Comments
 (0)