目录
本地:App.vue,components/component1.vue,store/index.js,
写在前面+效果图
本次是探索性质,肯定有一定差错和不足,我会继续学习。
不做详细的vue和vuex语法、功能介绍,因为文档讲得比我清楚,我主要是提供撰写的顺序思路,以及完整的代码。
目录在上面,自取所需。
效果图:
Vuex
Codepen:html+js+css
如何在这个界面使用vuex?只需要在html里写上:
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuex@3.6.2/dist/vuex.js"></script>
codepen这里的意思就是不分文件层级,所有js都在一个js里,html、css也是,确实很简洁。
一个可能更加通顺的思路
对于js部分,首先把框架写出来,三个部分:new Vue、vue的组件、Vuex部分
Const store = new Vuex.Store({
mutations:{
},
getters:{
},
actions:{
},
});
vue.component('c1',{
template:`
`,
data(){
},
computed(){
},
methods:{
},
});
vue.component('c2',{
});
New Vue({
el: '#app',
store,
created(){
this.$store.commit("loadTodos");
}
});
然后,根据界面里有什么,构想各个component应该长什么样,譬如我认为,我需要一个header,还需要一个content。
html:对的,用组件就这么简单明了。
<div id="app">
<header-component></header-component>
<content-component></content-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuex@3.6.2/dist/vuex.js"></script>
根据html设计思路,在Vue.component里填写template内容:譬如div、button,以及一些要用的变量,一开始只写个框,譬如<button>增加</button>,{{total}},先不考虑这个变量存不存在,以便于排除冗杂的信息;
接着,根据文字说明,具体地填写功能,譬如我要实现增加,我就要点这个按钮调用函数,所以我扩充为<button @click="addTodo">增加</button>:
Vue.component("header-component", {
template: `
<div class="header">
<div class="filter">
<button @click="myFilter('all')">全部</button>
<button @click="myFilter('finished')">已完成</button>
<button @click="myFilter('not-finished')">未完成</button>
<span>总共{{ total }}条,已完成{{ completed }}条,剩余{{ remaining }}条</span>
<button @click="clearCompleted">清除已完成</button>
<button @click="checkAll">全部完成</button>
<button class="headerAdd" @click="addTodo">增加新的TODO</button>
</div>
</div>
`,
// 以下省略
}
既然写了一些想实现的方法,譬如addTodo,那么接下来就在各个component的methods里写上要让vuex调用数据驱动的方法的大概样子(有点像先写个抽象类,之后再完善),格式都是this.$store.commit('vuex里的方法名',要传的变量);
变量也是如此,在computed里写。vuex里已有的变量用this.$store.state,要计算的变量用this.$store.getters(这个目前还不知道要不要计算,所以先写一个试试)
那么现在vue的部分完成了,要写vuex了。根据之前的这些commit、state、getters的内容,填充Vuex,先写mutation,再写getters,过程中会发现需要变量,就往state里加。大概长图片那样
- mutations和getters:每个函数的第一个变量都是state,修改state{}里的数据必须用这个前缀;第二个开始的参数是传入的,根据之前写的来
- 具体功能就在这里实现,这就是数据驱动的精妙之处,具体的操作都让vuex执行,不用vue的component之前传来传去的麻烦
- getters需要return,之前的computed也要写return,别忘了就是。
最后,进行功能检查:getters和computed用对了吗,dispatch和commit用对了吗,其他各种检查。那么vuex的功能差不多也完成了。
codepen这种情况下的总体代码:
html里:
<div id="app">
<header-component></header-component>
<content-component></content-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuex@3.6.2/dist/vuex.js"></script>
js里:
Vue.component("header-component", {
template: `
<div class="header">
<div class="filter">
<button @click="myFilter('all')">全部</button>
<button @click="myFilter('finished')">已完成</button>
<button @click="myFilter('not-finished')">未完成</button>
<span>总共{{ total }}条,已完成{{ completed }}条,剩余{{ remaining }}条</span>
<button @click="clearCompleted">清除已完成</button>
<button @click="checkAll">全部完成</button>
<button class="headerAdd" @click="addTodo">增加新的TODO</button>
</div>
</div>
`,
computed: {
total() {
return this.$store.state.todoList.length;
},
completed() {
return this.$store.getters.completed;
},
remaining() {
return this.$store.getters.remaining;
}
},
methods: {
myFilter(status) {
this.$store.commit("setFilterStatus", status);
},
clearCompleted() {
this.$store.commit("clearCompleted");
},
checkAll() {
this.$store.commit("checkAll");
},
addTodo() {
this.$store.commit("addTodo");
}
}
});
Vue.component("content-component", {
template: `
<div class="content">
<div class="todo-item" v-for="(item, index) in filteredTodoList" :key="item.id" transition="zj">
<input class="checkbox" type="checkbox" @click="check(index, item.id)" v-model="item.isChecked">
<input class="item-input" v-model="item.text" type="text" :disabled="item.isChecked" @blur="handleBlur()">
<input type="datetime-local" v-model="item.time" @blur="handleBlur">
<button @click="removeTodo(index, item.id)">删除</button>
</div>
</div>
`,
computed: {
filteredTodoList() {
return this.$store.getters.filteredTodoList;
}
},
methods: {
check(index, id) {
this.$store.commit("check", { index, id });
},
removeTodo(index, id) {
this.$store.commit("removeTodo", { index, id });
},
handleBlur() {
this.$store.commit("saveTodos");
}
}
});
const store = new Vuex.Store({
state: {
todoList: [],
filterStatus: "all"
},
getters: {
filteredTodoList(state) {
if (state.filterStatus === "finished") {
return state.todoList.filter((item) => item.isChecked);
} else if (state.filterStatus === "not-finished") {
return state.todoList.filter((item) => !item.isChecked);
} else {
return state.todoList;
}
},
total(state) {
return state.todoList.length;
},
completed(state) {
return state.todoList.filter((item) => item.isChecked).length;
},
remaining(state) {
return state.todoList.filter((item) => !item.isChecked).length;
}
},
mutations: {
setFilterStatus(state, status) {
state.filterStatus = status;
},
addTodo(state) {
state.todoList.unshift({
id: Number(Math.random().toString().substr(2, 10) + Date.now()).toString(
10
),
isChecked: false,
text: "",
time: new Date().toISOString().slice(0, 16)
});
localStorage.setItem("todoList1", JSON.stringify(state.todoList));
},
removeTodo(state, { index, id }) {
if (state.todoList[index].id === id) {
state.todoList.splice(index, 1);
localStorage.setItem("todoList1", JSON.stringify(state.todoList));
}
},
check(state, { index, id }) {
if (state.todoList[index].id === id) {
state.todoList[index].isChecked = !state.todoList[index].isChecked;
localStorage.setItem("todoList1", JSON.stringify(state.todoList));
}
},
checkAll(state) {
state.todoList.forEach((item) => {
item.isChecked = true;
});
localStorage.setItem("todoList1", JSON.stringify(state.todoList));
},
clearCompleted(state) {
state.todoList = state.todoList.filter((item) => !item.isChecked);
localStorage.setItem("todoList1", JSON.stringify(state.todoList));
},
saveTodos(state) {
localStorage.setItem("todoList1", JSON.stringify(state.todoList));
},
loadTodos(state) {
const tmp = localStorage.getItem("todoList1");
if (tmp) {
state.todoList = JSON.parse(tmp);
} else {
state.todoList = [
{
id: Number(Math.random().toString().substr(2, 10) + Date.now()).toString(
10
),
text: "请点击上方的添加按钮添加事件",
isChecked: false,
time: new Date().toISOString().slice(0, 16)
}
];
}
}
}
});
new Vue({
el: "#app",
store,
created() {
this.$store.commit("loadTodos");
}
});
css部分请自由发挥。
本地:App.vue,components/component1.vue,store/index.js,main.js
内容还是基本一样的,本地的问题主要是看东西放在哪个文件夹。
首先你得装了vue;然后在一个文件夹启动环境;而且要在同一个文件夹装vuex。
这样的话,你将会看到的结构:(TEST_VUE是根目录;store文件夹本来没有,自己建一个。)
App.vue同级还需要一个main.js
请看各个文件
App.vue几乎完全一样:
<template>
<div id="app">
<header-component></header-component>
<content-component></content-component>
</div>
</template>
<style>
</style>
store/index.js:放的是vuex的东西,记得import和Vue.use(vuex)
注意export default new Vuex.Store代替了之前的new store = Vuex.Store,不改的话会报错:We‘re sorry but doesn’t work properly without JavaScript enabled. Please enable it to continue
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
todoList: [],
filterStatus: "all"
},
getters: {
filteredTodoList(state) {
if (state.filterStatus === "finished") {
return state.todoList.filter((item) => item.isChecked);
} else if (state.filterStatus === "not-finished") {
return state.todoList.filter((item) => !item.isChecked);
} else {
return state.todoList;
}
},
total(state) {
return state.todoList.length;
},
completed(state) {
return state.todoList.filter((item) => item.isChecked).length;
},
remaining(state) {
return state.todoList.filter((item) => !item.isChecked).length;
}
},
mutations: {
setFilterStatus(state, status) {
state.filterStatus = status;
},
addTodo(state) {
state.todoList.unshift({
id: Number(Math.random().toString().substr(2, 10) + Date.now()).toString(
10
),
isChecked: false,
text: "",
time: new Date().toISOString().slice(0, 16)
});
localStorage.setItem("todoList1", JSON.stringify(state.todoList));
},
removeTodo(state, { index, id }) {
if (state.todoList[index].id === id) {
state.todoList.splice(index, 1);
localStorage.setItem("todoList1", JSON.stringify(state.todoList));
}
},
check(state, { index, id }) {
if (state.todoList[index].id === id) {
state.todoList[index].isChecked = !state.todoList[index].isChecked;
localStorage.setItem("todoList1", JSON.stringify(state.todoList));
}
},
checkAll(state) {
state.todoList.forEach((item) => {
item.isChecked = true;
});
localStorage.setItem("todoList1", JSON.stringify(state.todoList));
},
clearCompleted(state) {
state.todoList = state.todoList.filter((item) => !item.isChecked);
localStorage.setItem("todoList1", JSON.stringify(state.todoList));
},
saveTodos(state) {
localStorage.setItem("todoList1", JSON.stringify(state.todoList));
},
loadTodos(state) {
const tmp = localStorage.getItem("todoList1");
if (tmp) {
state.todoList = JSON.parse(tmp);
} else {
state.todoList = [
{
id: Number(Math.random().toString().substr(2, 10) + Date.now()).toString(
10
),
text: "请点击上方的添加按钮添加事件",
isChecked: false,
time: new Date().toISOString().slice(0, 16)
}
];
}
}
}
});
main.js:注意下面的东西路径正确,注意header-component是最终使用在html的名字,不能写错;注意这里用了mount,和之前不一样了
import Vue from 'vue';
import store from './store/index.js';
import app from './App.vue';
import HeaderComponent from './components/header.vue';
import ContentComponent from './components/content.vue';
Vue.component('header-component', HeaderComponent);
Vue.component('content-component', ContentComponent);
new Vue({
store,
render: (h) => h(app)
}).$mount('#app');
components/content.vue:注意export default的变化。header那个也类似地调整一下。
<template>
<div class="content">
<div class="todo-item" v-for="(item, index) in filteredTodoList" :key="item.id" transition="zj">
<input class="todo-item__checkbox" type="checkbox" @click="check(index, item.id)" v-model="item.isChecked">
<input class="todo-item__item-input" v-model="item.text" type="text" :disabled="item.isChecked" @blur="handleBlur()">
<input type="todo-item__datetime-local" v-model="item.time" @blur="handleBlur">
<button @click="removeTodo(index, item.id)">删除</button>
</div>
</div>
</template>
<script>
export default {
computed: {
filteredTodoList() {
return this.$store.getters.filteredTodoList;
}
},
methods: {
check(index, id) {
this.$store.commit("check", { index, id });
},
removeTodo(index, id) {
this.$store.commit("removeTodo", { index, id });
},
handleBlur() {
this.$store.commit("saveTodos");
}
}
};
</script>
<style>
</style>
差不多就完成了。
其他的具体配置我也不懂了,主要还是跟着其他人的教程进行安装,有问题就找攻略修。希望大家都写得顺利!