首先新建一个vue项目,然后install vuex。
在建好的项目中,首先在src文件夹下新建一个store.js,当然,如果你比较追求完美,可以新建一个store文件夹,里面再创建一个js,store.js文件中,首先需要引入vue和vuex,然后再将vuex全局注入到vue中,就想这样:
import Vue from 'vue';
import Vuex from 'vuex'
// vuex注入到vue中
Vue.use(Vuex);
然后新建一个仓库:
export default new Vuex.Store({})
在仓库中先写好state,mutations,actions,getters和setters,就是vuex的全家桶,state中存放需要进行计算和操作的数据
state:{ //存放需要进行计算和操作的数据
count:0, //数量
todoList:[ //正在进行中的事件以及是否完成
{todo:"吃饭",isComplete:false},
{todo:"睡觉",isComplete:false},
{todo:"打豆豆",isComplete:true},
]
},
对了,还需要注意的是,你需要将store,在入口文件main.js中引入,一定要记得加上这一步:
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
ok,再回来,我们在state中定义好数据以后,在components文件夹下新建一个vue文件,todoList,然后写上列表样式,就是未完成的部分的列表:
<template>
<div>
<Input/>
<ul>
<!-- 显示未完成的 -->
<li v-for="(todo,index) in todoList" :key="index">
<input type="checkbox"/>
<span>{{todo.todo}}<button @click="del(todo)">删除</button></span>
</li>
</ul>
<complete></complete>
</div>
</template>
<script>
记得在style样式中加上
ul{
list-style:none;
margin:0;
}
去掉小点。
然后再新建一个vue文件,将todoList引入,展示出来,就是说新建的vue文件是todoList的父组件。
todoList中的v-for循环中的todo是从store中获取的,用辅助函数去获取,首先引入辅助函数
import {mapState,mapActions} from 'vuex'
computed:{
//返回一个对象(展开运算符的效果)
// count(){
// return count
// }
// 当计算属性名和state属性名一致的时候,传数组
// ...mapState(["todoList","count"])
...mapState({ //计算属性的名字和state里面属性的名字不一样
count:"count", //字符串代表你传给后台的state里面的值
todoList:"todoList"
})
},
接下来就是写完成部分,创建一个vue文件isComplete,然后作为todoList的子组件引入todoList。
在isComplete文件中,首先我们需要获取到完成的事件,那么就要在store.js中的getters中写个方法,让它过滤掉未完成的事情。
getters相当于store的计算属性,只有当它的依赖改变之后,才会触发此函数,而它的依赖就是state,看代码:
getters:{//相当于store的计算属性,只有当他的依赖改变之后才会触发此函数
complete(state,getters){ //state就是它的依赖
// console.log(state)
//过滤掉未完成的,返回已经完成的项
return state.todoList.filter(item => item.isComplete!==false)
},
}
那么,接下来我就可以在isComplete.vue这个文件下,v-for li,看代码:
<template>
<div>
<h1>已完成的选项</h1>
<ul>
<li v-for="(item,index) in complete" :key="index">{{item.todo}} <button @click="del(item)">删除</button></li>
</ul>
</div>
</template>
为什么给个index呢,是为了之后的删除,这个等下再讲。之后我们在isComplete.vue这个文件下,引入mapGetters辅助函数:
import {mapGetters} from "vuex"
export default{
computed:{
...mapGetters([
"complete"
])
},
}
接下来我们做输入选项的部分,因为todoList本来就类似于记事本,输入内容,将内容添加到下面的列表中。ok,我们来创建一个vue文件,取名为input,简单明了,input是和isComplete一样,作为todoList的子组件,所以我们把它引入todoList。然后,我们写input的样式,代码:
<template>
<div>
<input type="text" v-model="todo" >
<button @click="add(todo)">添加</button>
</div>
</template>
add方法中的todo参数,是我在data中自己定义的一个字符串,然后再methods中写add这个方法,
add这个方法是为了触发mutation中的方法,我在store中的mutation下写下add方法,代码如下:
add(state,payload){ //载荷是数据
let item = JSON.parse(payload)
state.todoList.push(item)
},
至于为什么要把payload转换成JSON对象呢,等下说。
mutation中的事件需要actions来提交,所以,我们在actions中写上addItem的方法,用来提交mutation中的方法,代码如下:
actions:{ //异步执行mutation的方法
addItem({commit},payload){
let todoItem = {
todo:payload, //携带的数据
isComplete:false
};
todoItem = JSON.stringify(todoItem)
console.log(payload)
// commit('add',payload)//此处不要漏写了mutation里面的方法
commit('add',todoItem)
},
由于action传递的参数只能是字符串,所以只能把对象转成字符串,至于commit,你console.log一下store,就能看到,这是actions的属性之一。所以,mutation中的方法需要将JSON字符串转换成JSON对象追加到state的todoList对象中。然后我们来做个功能表,就是说每当你添加一条数据,点击添加按钮的时候,输入框中的内容都会被清空,代码如下:
add(todo){
this.todo="";
console.log(222);
this.addItem(todo);
},
...mapActions(["addItem"])
我们先是通过mapActions来提交mutations中的方法,然后因为每次添加都要清空嘛,所以,我在add这个方法中先每次清空掉输入框中的内容,然后,调用一次addItem ,l里面传上参数todo。
接下来写删除。
同样,在mutations中写下del方法,然后在actions中写一个方法去提交它,代码如下:
del(state,index){
console.log(index);
state.todoList.splice(index,1);
}
handleDel({commit,state},item){
// 获取下标
let list=[],
cindex=null;
state.todoList.map((i,index)=>{//为了获取到下标,因为要通过下标来删除对应的事件
if(i.todo===item.todo){
cindex=index;
}
})
commit('del',cindex)//此处不要漏写mutation里面的方法
}
在TodoList中,我们通过dispatch来触发store中Actions中的删除方法,代码如下:
del(item){
this.$store.dispatch("handleDel",item)
}
完整代码:
store.js
import Vue from 'vue';
import Vuex from 'vuex'
// vuex注入到vue中
Vue.use(Vuex);
export default new Vuex.Store({ //仓库
state:{ //存放需要进行计算和操作的数据
count:0, //数量
todoList:[ //正在进行中的事件以及是否完成
{todo:"吃饭",isComplete:false},
{todo:"睡觉",isComplete:false},
{todo:"打豆豆",isComplete:true},
]
},
// 需求:返回已经完成的选项
// 怎么做:1.需要一个方法来返回已经完成的选项并且让部分子组件得到
// mutation中写需要操作的方法,由commit触发,mutation是同步的
mutations:{
add(state,payload){ //载荷是数据
let item = JSON.parse(payload)
state.todoList.push(item)
},
del(state,index){
console.log(index);
state.todoList.splice(index,1);
}
},
actions:{ //异步执行mutation的方法
addItem({commit},payload){
let todoItem = {
todo:payload,
isComplete:false
};
todoItem = JSON.stringify(todoItem)
console.log(payload)
// commit('add',payload)//此处不要漏写了mutation里面的方法
commit('add',todoItem)
console.log(1111);
},
handleDel({commit,state},item){
// 获取下标
let list=[],
cindex=null;
state.todoList.map((i,index)=>{
if(i.todo===item.todo){
cindex=index;
}
})
commit('del',cindex)//此处不要漏写mutation里面的方法
}
},
getters:{//相当于store的计算属性,只有当他的依赖改变之后才会触发此函数
complete(state,getters){ //state就是它的依赖
// console.log(state)
//返回已经完成的项
return state.todoList.filter(item => item.isComplete!==false)
},
// 如果要接受参数,那么需要返回一个函数
// test:function(state){
// return function(val){
// return state.count + val
// }
// },
test:state => val =>state.count+val
}
})
view.vue
<template>
<div>
<h1>ToDoList</h1>
<todoList></todoList>
</div>
</template>
<script>
import todoList from '@/components/HelloWorld.vue'
// 注册
export default {
components:{
todoList
},
}
</script>
<style scoped>
</style>
todoList.vue
<template>
<div>
<Input/>
<ul>
<!-- 显示未完成的 -->
<li v-if="!todo.isComplete" v-for="(todo,index) in todoList" :key="index">
<input type="checkbox" v-model="todo.isComplete"/><!--因为点击勾选就是已完成,不选就是未完成,也可通过mutation写方法来改变状态-->
<span>{{todo.todo}}<button @click="del(todo)">删除</button></span>
</li>
</ul>
<complete></complete>
</div>
</template>
<script>
//通过辅助函数
import {mapState,mapActions} from 'vuex';
import complete from './isComplete.vue'
import Input from './input.vue'
export default{
components:{
complete,
Input
},
// data(){
// return{
// todoList:this.$store.state.todoList //这边一定是从store中获取的
// }
// },
computed:{
//返回一个对象(展开运算符的效果)
// count(){
// return count
// }
// 当计算属性名和state属性名一致的时候,传数组
// ...mapState(["todoList","count"])
...mapState({ //计算属性的名字和state里面属性的名字不一样
count:"count", //字符串代表你传给后台的state里面的值
todoList:"todoList"
})
},
methods:{
// del(index){
// this.$store.dispatch("handleDel",index)
//
// }
del(index){
this.$store.dispatch("handleDel",index)
}
}
}
</script>
<style scoped>
ul{
list-style:none;
margin:0;
}
</style>
isComplete.vue
<!-- 已完成的 -->
<template>
<div>
<h1>已完成的选项</h1>
<ul>
<li v-for="(item,index) in complete" :key="index">{{item.todo}} <button @click="del(item)">删除</button></li>
</ul>
</div>
</template>
<script>
import {mapGetters,mapActions} from "vuex"
export default{
data(){
return{
}
},
computed:{
...mapGetters([
"complete"
])
},
methods:{
del(item){
this.$store.dispatch("handleDel",item)
}
// del(index){
// this.$store.dispatch("handleDel","complete")
// }
},
mounted(){
// let complete = this.$store.getters.complete;
// console.log(complete)
}
}
</script>
<style>
</style>
input.vue
<template>
<div>
<input type="text" v-model="todo" >
<button @click="add(todo)">添加</button>
</div>
</template>
<script>
import { mapActions } from "vuex";
export default {
data(){
return{ //输入框输入的
todo:"",
}
},
methods:{
// add(){
// let todoItem={
// todo:this.todo,
// isComplete:false
// }
// //由于action传递的参数只能是字符串,所以只能把对象转成字符串
// todoItem = JSON.stringify(todoItem);
// this.$store.dispatch("addItem",todoItem)
// this.todo = ""
//
// },
add(todo){
this.todo="";
console.log(222);
this.addItem(todo);
},
...mapActions(["addItem"])
//把todoItem传递到mutation
//dispatch是 调用actions的方法,第一个值是actions的方法,第二个是带过去的值
},
}
</script>
<style>
</style>