前言
Vuex 是为 Vue 专门制定的状态管理工具。其核心思想是将所有的状态集中在顶层进行统一管理。通过不同的事件类型,进行统一分发不同的状态,再通过状态去影响视图层。
在使用前执行npm install Vuex
下载 Vuex。
案例需求
实现一个 todoList (任务管理功能),包含的功能有:
- 获取初始任务列表;
- 添加待办事项;
- 编辑任务状态(将任务置为未完成或者已完成);
- 删除待办事项;
- 查询任务列表(按状态已完成/未完成/所有查询)。
第一步:state
state 是驱动应用的数据源,是一棵单一状态树。根据案例所示,需要创建一个 taskList,用来储存任务列表信息。
state: {
taskList:[],//初始化任务列表
filter:'all'//初始化任务状态,默认显示所有列表
},
第二步:Getter
如果多个组件需要使用到同一个变量,可以封装在 Getter 中。或者 Getter 中也可以改变状态。根据案例所示,需要创建一个改变 filter 状态的方法 changeFilter,是否展示任务项方法 isDisplay。
//是否展示任务项
isDisplay:state => item =>{
if(state.filter == 'all'){
return true
};
if(state.filter == 'completed'){
if(item.done){
return true
}else {
return false
}
}
if(state.filter == 'uncompleted'){
if(!item.done){
return true
}else {
return false
}
}
},
//改变过滤状态
changeFilter: state =>flag=> {
state.filter = flag;
},
第三步:Mutation
更改 state 状态的唯一办法就是 Mutation,并且 Mutation 必须是同步函数。根据案例所示,需要创建添加任务方法 addTodo,获取初始任务列表方法 getInitData,编辑任务状态方法 changeStatus、删除任务方法 delTask。
//添加任务列表
addTodo(state,item){
//新添加item的id根据列表最后的id自增
item.id = state.taskList[state.taskList.length-1].id+1;
state.taskList = [...state.taskList,item];
},
//获取初始任务列表
getInitData(state,arr){
state.taskList = arr;
},
//修改任务状态
changeStatus(state,item){
item.done = !item.done;
},
//删除任务
delTask(state,index){
state.taskList.splice(index,1);
}
第四步:Action
Action 中主要是分发 Mutation,与 Mutation 的区别是可以在这里处理异步操作。比如调取接口获取初始任务列表信息。
//模拟异步获取任务列表
getDataAsync (context) {
var arr = [];
setTimeout(() => {
arr = [{
text:"国际会议",id:1,done:true
}];
context.commit('getInitData',arr);
}, 1000)
}
}
第五步:属性或者方法整合
mapState:是将所有的 State 整合在一起。
mapGetters:是将所有的 Getters 整合在一起。
mapMutations:是将所有的 Mutations 整合在一起。
mapActions:是将所有的 Actions 整合在一起。
以上带 map 的方法是一个整合作用,在使用多个 state 或者方法时可以直接用 this.的形式,而不用 this.$ store.形式,比如对于被 state 储存的 taskList。在组件中使用时可以直接this.taskList,而不用 this.$store.state.taskList。
实现功能
- 在项目跟目录新建 store 文件夹,在其文件夹下新建 index.js。
index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
//创建Store实例
const store = new Vuex.Store({
state: {
taskList:[],//初始化任务列表
statusList:[
{
label:"所有",
flag:'all'
},{
label:"已完成",
flag:'completed'
},{
label:"未完成",
flag:'uncompleted'
}
],//任务状态列表
filter:'all'//初始化任务状态
},
getters: {
//是否展示任务项
isDisplay:state => item =>{
if(state.filter == 'all'){
return true
};
if(state.filter == 'completed'){
if(item.done){
return true
}else {
return false
}
}
if(state.filter == 'uncompleted'){
if(!item.done){
return true
}else {
return false
}
}
},
//改变过滤状态
changeFilter: state =>flag=> {
state.filter = flag;
},
},
mutations: {
//添加任务列表
addTodo(state,item){
//新添加item的id根据列表最后的id自增
item.id = state.taskList[state.taskList.length-1].id+1;
state.taskList = [...state.taskList,item];
},
//获取初始任务列表
getInitData(state,arr){
state.taskList = arr;
},
//修改任务状态
changeStatus(state,item){
item.done = !item.done;
},
//删除任务
delTask(state,index){
state.taskList.splice(index,1);
}
},
actions: {
//模拟异步获取任务列表
getDataAsync (context) {
var arr = [];
setTimeout(() => {
arr = [{
text:"国际会议",id:1,done:true
}];
context.commit('getInitData',arr);
}, 1000)
}
}
});
export default store;
- 新建 Vuex.vue 文件,编写功能代码。
<template>
<div class="vuex-m-20">
<div class="vuex-tx-c">todo list 案例</div>
<div class="vuex-m-20">
<input type="text" v-model="text"><button @click="add">添加待办</button>
<div v-for="(item,index) in taskList" v-if="show(item)" >
<span :class="item && item.done?'vuex-line':''" @click="operate('change',item)">{{item.text}}</span><span class="vuex-ml-20" @click="operate('del',index)">删除</span>
</div>
</div>
<div>
<div class="vuex-mtb-20">
<span @click="query(item.flag)" class="vuex-ml-20" v-for="item in statusList" >{{item.label}}</span>
</div>
</div>
</div>
</template>
<script>
import { mapState,mapGetters,mapMutations,mapActions} from 'vuex';
export default {
name: 'Vuex',
data () {
return {
text:""
}
},
created(){
//获取初始任务列表
this.getDataAsync();
},
computed: {
//监听任务列表变化
taskList(){
return this.taskList;
},
//任务状态列表
statusList(){
return this.statusList;
},
//过滤任务列表
show(){
return item =>{
return this.isDisplay(item);
}
},
...mapGetters([
'changeFilter',
'isDisplay'
]),
...mapState([
'taskList',
'statusList',
'filter'
])
},
methods: {
...mapMutations([
'addTodo',
'changeStatus',
'delTask'
]),
...mapActions([
'getDataAsync'
]),
add(){
// 添加任务项
this.addTodo({
text:this.text,done:false
});
},
//按完成状态查询任务列表
query(status){
this.changeFilter(status);
},
//编辑任务状态和删除任务
operate(str,param){
if(str == 'change'){
this.changeStatus(param);
}else {
this.delTask(param)
}
}
}
}
</script>
<style scoped>
.vuex-m-20{
margin: 20px;
}
.vuex-line{
text-decoration:line-through
}
.vuex-ml-20{
margin-left: 20px;
}
.vuex-tx-c{
text-align: center;
}
.vuex-mtb-20{
margin: 20px 0;
}
</style>