Vuex深入浅出,实例讲解。
**Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
调试工具:vue devtools
Vuex就像眼镜:您自会知道什么时候需要它**
首先创建一个vue项目之后,安装vuex
cnmp install vuex --save
1,state的用法
在store中定义数据 ,在组件中直接使用
//这个文件在 store包下的index.js就是用来做状态管理的 ,并且将这个文件引入到全局文件中
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//暴露的第一种方式
export default new Vuex.Store({
//相当于组件中的data,专门用来存放全局的数据,他是一个对象
state:{
//定义一个变量
num:0
},
getters:{},
mutations:{},
actions:{},
modules:{}
})
//暴露的第二种方式
/*
const store=new Vuex.Store({
})
export default store
*/
将创建的store仓库导入到main.js中
创建一个views的包来创建组件
Home.vue(第一种方式引入仓库中的值)
<template>
<div class="home">
<!-- 使用$store 来引入仓库中的值-->
<h1>Home页面的数字={{$store.state.num}}</h1>
</div>
</template>
<script>
export default {
}
</script>
About.vue(第二种方式引入仓库中的值)
<template>
<div class="about">
<h1>About页面的数字={{num}}</h1>
</div>
</template>
<script>
export default {
// 使用 computed 来给变量赋值 this指向的是整个vue的实例,直接指向仓库的值
computed:{
num(){
return this.$store.state.num
}
}
}
</script>
Btn.vue 组件
<template>
<div>
<button @click="$store.state.num++">点击加1</button>
</div>
</template>
<script>
export default {
data(){
return{
}
},
}
</script>
<style scoped>
</style>
将各个组件来引入到App.vue组件中
<template>
<div id="app">
<Home></Home>
<About></About>
<Btn></Btn>
</div>
</template>
<script>
//引入home 组件
import Home from "./views/Home";
//引入about组件
import About from "./views/About";
//引入btn组件
import Btn from "./views/Btn";
export default {
// 注册组件
components: {
Home,
About,
Btn
}
}
</script>
效果显示页面
2,getters的用法,主要作用就是声明使用,减少代码的冗余,将组件中的统一使用的computed都放在getters里面来操作
这个属性的使用方法,好像看起来
s
t
o
r
e
.
s
t
a
t
e
.
n
u
m
和
store.state.num 和
store.state.num和store.getters.getNum差不多,但是具体来看的话,一个直接得到的属性的值,一个是通过方法的得到的返回值,类似于面型对象的get方法
store中的index.js页面
//这个文件的作用就是做转状体管理
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//暴露的第一种方式
export default new Vuex.Store({
//相当于组件中的data,专门用来存放全局的数据,他是一个对象
state:{
//定义一个变量
num:0
},
//getters相当于组件中到的computed,getter是全局的,computed是组件内部使用的
//可以将 computed中的 num(){} 放在getters中统一全局使用
getters:{
//第一种方式
/* num(){
return this.$store.state.num
}*/
//第二种方式 参数为state,指向 上面的state
getNum(state){
return state.num
}
},
mutations:{},
actions:{},
modules:{}
})
//暴露的第二种方式
/*
const store=new Vuex.Store({
})
export default store
*/
通过getters的设置之后,我们可以直接通过getters方法直接返回数据,就不直接使用computed属性了,所以Abou.vue可以改为以下形式
<template>
<div class="about">
<h1>About页面的数字={{$store.getters.getNum}}</h1>
</div>
</template>
<script>
export default {
}
</script>
页面展示
3,mutation的用法
mutation是更改store中的状态的唯一方法是提交mutation,Vuex中mutation是非常类似于每一个mutation都有一个字符串的事件类型和一个回调函数,这个回调函数就是我们实际进行修改的状态的地方,并且他会接收state作为第一个参数,类似于组件中methods,在这个属性中创建方法,来修改state中的属性的值
store中的index.js页面
//这个文件的作用就是做转状体管理
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//暴露的第一种方式
export default new Vuex.Store({
//相当于组件中的data,专门用来存放全局的数据,他是一个对象
state:{
//定义一个变量
num:0
},
//getters相当于组件中到的computed,getter是全局的,computed是组件内部使用的
//可以将 computed中的 num(){} 放在getters中统一全局使用
getters:{
//第一种方式
/* num(){
return this.$store.state.num
}*/
//第二种方式 参数为state,指向 上面的state
getNum(state){
return state.num
}
},
//mutations相当于组件中的methods,但是他不能使用异步方法(定时器,axios),这个属性存放方法来修改state属性的值
mutations:{
//创建一个方法,来修改state属性的值,参数就是state
//payload是一个形参,如果组件在commit时,有传这个参数过来,就存在,如果没有传参过来,就是undefined
increase(state,payoad){
state.num+=payoad ? payoad :1;
}
},
actions:{},
modules:{}
})
//暴露的第二种方式
/*
const store=new Vuex.Store({
})
export default store
*/
Btn.vue页面代码
<template>
<div>
<button @click="addFn">点击加1</button>
</div>
</template>
<script>
export default {
methods: {
addFn(){
//调用仓库中的mutation属性中的方法,这时不传payload,每次只加1
this.$store.commit('increase')
/* //这个是加入payload的参数,每次加6
*this.$store.commit('increase',6)
*/
}
}
}
</script>
<style scoped>
</style>
页面效果
4,actions的用法
actions属性是专门处理异步请求的,实际修改状态值的是mutation
action函数 接收一个与store实例具有相同方法的和属性的context对象,因此你可以调用context.commit,提交一个mutation,或者通过
context.getters 来获取state和 getters。在之后的Moudles被介绍到的时候,你就知道,context对象为什么不是store实例本身了
简单来说就是有了context对象就可以使用commit
store中的index.js页面,在 action属性中添加异步的犯法,实际修改状态值的是mutation
//这个文件的作用就是做转状体管理
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//暴露的第一种方式
export default new Vuex.Store({
//相当于组件中的data,专门用来存放全局的数据,他是一个对象
state:{
//定义一个变量
num:0
},
//getters相当于组件中到的computed,getter是全局的,computed是组件内部使用的
//可以将 computed中的 num(){} 放在getters中统一全局使用
getters:{
//第一种方式
/* num(){
return this.$store.state.num
}*/
//第二种方式 参数为state,指向 上面的state
getNum(state){
return state.num
}
},
//mutations相当于组件中的methods,但是他不能使用异步方法(定时器,axios),这个属性存放方法来修改state属性的值
mutations:{
//创建一个方法,来修改state属性的值,参数就是state
//payload是一个形参,如果组件在commit时,有传这个参数过来,就存在,如果没有传参过来,就是undefined
increase(state,payoad){
state.num+=payoad ? payoad :1;
},
//创建一个方法来修改状态值
decrease(state){
state.num--;
}
},
//actions属性是专门处理异步请求的,实际修改状态值的是mutations
//action函数 接收一个与store实例具有相同方法的和属性的context对象,因此你可以调用context.commit,提交一个mutation,或者通过
//context.getters 来获取state和 getters。在之后的Moudles被介绍到的时候,你就知道,context对象为什么不是store实例本身了
//简单来说就是有了context对象就可以使用commit
actions:{
//点击减1按钮,实现 时间过去一秒之后再 执行减1的操作的异步方法
decreaseAsync(context){
context.commit('decrease')
}
},
modules:{}
})
//暴露的第二种方式
/*
const store=new Vuex.Store({
})
export default store
*/
About.vue使用映射来给拿仓库中的store的state中的getNumf方法 mapGetters
<template>
<div class="about">
<!-- 直接访问仓库中的getters中的方法 不须要添加 computed-->
<!-- <h1>About页面的数字={{$store.getters.getNum}}</h1>-->
<!--使用映射来获取 getters方法中的方法,必须要添加 computed-->
<h1>About页面的数字={{getNum}}</h1>
</div>
</template>
<script>
//使用映射导入 vuex中所有的getters都导入过来
import { mapGetters } from 'vuex'
export default {
computed:{
...mapGetters(['getNum'])
}
}
</script>
Home.vue使用映射来给拿仓库中的store的getters中的num值 mapState
<template>
<div class="home">
<!-- 使用$store 来引入仓库中的值 不须要添加 computed-->
<!-- <h1>Home页面的数字={{$store.state.num}}</h1>-->
<!-- 使用映射的方法来获取 state中的值,使用的是mapState数组 必须要添加 computed属性-->
<h1>Home页面的数字={{num}}</h1>
</div>
</template>
<script>
//{ mapState } 是把整个vuex中的state整个映射过来
import { mapState } from 'vuex'
export default {
// 使用 computed属性
computed:{
//使用这个方法来拿到 mapState,mampstate的参数就是一个数组,数组的成员就是 仓库中给store的state属性
...mapState(['num'])
}
}
</script>
Btn.vue 使用映射来得到mutation 和action中的方法 mapMutations , mapActions
<template>
<div>
<!-- 不用映射方法-->
<!-- <button @click="addFn">点击加1</button>-->
<!--<!– 可以指直接访问 仓库中mutations中的方法–>
<button @click="$store.commit('decrease')">点击减1</button>-->
<!-- <button @click="reduceFn">点击减1</button>-->
<!-- 使用映射方法-->
<button @click="increase()">点击加1</button>
<button @click="decreaseAsync()">点击加1</button>
</div>
</template>
<script>
//导入映射,再调用的时候要 放在 methods属性中
import { mapMutations , mapActions} from 'vuex'
export default {
methods: {
addFn(){
//调用仓库中的mutation属性中的方法,这时不传payload,每次只加1
this.$store.commit('increase')
/* //这个是加入payload的参数,每次加6
this.$store.commit('increase',6)*/
},
reduceFn(){
//执行异步方法 action中的使用dispatch来执行
this.$store.dispatch('decreaseAsync');
},
/*
* 调用映射中的方法
* */
...mapActions(['decreaseAsync']),
...mapMutations(['increase'])
}
}
</script>
<style scoped>
</style>
显示效果
5,仓库拆分写法,将仓库中的属性都独立出来
strore中的所有属性,都可以拆分成单独的js文件来书写。
index.js文件
//这个文件的作用就是做转状体管理
import Vue from 'vue'
import Vuex from 'vuex'
//导入拆分的state
import state from "./state";
//导入拆分的getters
import getters from "./getters";
//导入拆分的mutaion
import mutations from "./mutations";
//导入拆分的actions
import actions from "./actions";
//导入拆分的moudels
import modules from "./modules";
//表示使用 vuex
Vue.use(Vuex)
//暴露的第一种方式
export default new Vuex.Store({
//相当于组件中的data,专门用来存放全局的数据,他是一个对象
state,
//getters相当于组件中到的computed,getter是全局的,computed是组件内部使用的
//可以将 computed中的 num(){} 放在getters中统一全局使用
getters,
//mutations相当于组件中的methods,但是他不能使用异步方法(定时器,axios),这个属性存放方法来修改state属性的值
mutations,
//actions属性是专门处理异步请求的,实际修改状态值的是mutations
//action函数 接收一个与store实例具有相同方法的和属性的context对象,因此你可以调用context.commit,提交一个mutation,或者通过
//context.getters 来获取state和 getters。在之后的Moudles被介绍到的时候,你就知道,context对象为什么不是store实例本身了
//简单来说就是有了context对象就可以使用commit
actions,
modules
})
//暴露的第二种方式
/*
const store=new Vuex.Store({
})
export default store
*/
state.js文件
export default {
//定义一个变量
num:0
}
getters.js文件
export default {
//第一种方式
/* num(){
return this.$store.state.num
}*/
//第二种方式 参数为state,指向 上面的state
getNum(state){
return state.num
}
}
mutations.js文件
export default {
//创建一个方法,来修改state属性的值,参数就是state
//payload是一个形参,如果组件在commit时,有传这个参数过来,就存在,如果没有传参过来,就是undefined
increase(state,payoad){
state.num+=payoad ? payoad :1;
},
//创建一个方法来修改状态值
decrease(state){
state.num--;
}
}
actions.js文件
export default {
//点击减1按钮,实现 时间过去一秒之后再 执行减1的操作的异步方法
decreaseAsync(context){
context.commit('decrease')
}
}
modules.js文件
export default {
}
6,modules
我们的store可以认为是一个主模块,他下边可以分解为多个子模块,子模块可以单独拎出来写,写完再导入主模块中。
就比如users模块举例,users模块也可以拥有state,getters,mutations,和actions,所有的属性和方法该怎么写就怎么写。但是再users中index.js文件中,需要写入
namespace:true 命名空间
然后在store的index.js中引入到moudles中
在组件中获取值的方法
$store.state.users.nickName
在组件中引入子模块方法
//在组件触发子模块的方法:
<script>
//{ mapState } 是把整个vuex中的state整个映射过来
import { mapState,mapMutations } from 'vuex'
//使用methods来访问 store中的方法
methods:{
//调用user模块中的chanegeNickName的方法,并且需要指定确定路径的方法
...mapMutations({
'changeNickName':"changeNickName"
})
</script>
实例说明
主模块index.js
//这个文件的作用就是做转状体管理
import Vue from 'vue'
import Vuex from 'vuex'
//导入拆分的state
import state from "./state";
//导入拆分的getters
import getters from "./getters";
//导入拆分的mutaion
import mutations from "./mutations";
//导入拆分的actions
import actions from "./actions";
import modules from "./modules";
//表示使用 vuex
Vue.use(Vuex)
//暴露的第一种方式
export default new Vuex.Store({
//相当于组件中的data,专门用来存放全局的数据,他是一个对象
state,
//getters相当于组件中到的computed,getter是全局的,computed是组件内部使用的
//可以将 computed中的 num(){} 放在getters中统一全局使用
getters,
//mutations相当于组件中的methods,但是他不能使用异步方法(定时器,axios),这个属性存放方法来修改state属性的值
mutations,
//actions属性是专门处理异步请求的,实际修改状态值的是mutations
//action函数 接收一个与store实例具有相同方法的和属性的context对象,因此你可以调用context.commit,提交一个mutation,或者通过
//context.getters 来获取state和 getters。在之后的Moudles被介绍到的时候,你就知道,context对象为什么不是store实例本身了
//简单来说就是有了context对象就可以使用commit
actions,
//这是一个主模块,在这个主模块可以引用 子模块
modules,
})
//暴露的第二种方式
/*
const store=new Vuex.Store({
})
export default store
*/
主模块moudles.js
import users from './users/index'
export default {
users
}
users模块index.js
import state from "./state";
import getters from "./getters";
import mutations from "./mutations";
import actions from "./actions";
export default {
//命名空间,可以通过users(包名)来访问 属性
namespace:true,
state,
getters,
mutations,
actions,
modules:{}
}
users子模块的state.js文件
export default {
nickName:'孙悟空',
token:'jiasfjasdfj'
}
users子模块的mutations.js文件
//创建一个方法来将孙悟空改为猪八戒
export default {
changeNickName(state){
state.nickName='猪八戒';
}
}
users子模块的acitons.js 和 getters.js都为空
Home.vue组件
<template>
<div class="home">
<!-- 使用$store 来引入仓库中的值 不须要添加 computed-->
<!-- <h1>Home页面的数字={{$store.state.num}}</h1>-->
<!-- 使用映射的方法来获取 state中的值,使用的是mapState数组 必须要添加 computed属性-->
<h1>Home页面的数字={{num}}</h1>
<li>{{$store.state.users.nickName}}</li>
<button @click="changeNickName()">将孙悟空改为猪八戒</button>
</div>
</template>
<script>
//{ mapState } 是把整个vuex中的state整个映射过来
import { mapState,mapMutations } from 'vuex'
export default {
// 使用 computed属性来访问 store中属性
computed:{
//使用这个方法来拿到 mapState,mampstate的参数就是一个数组,数组的成员就是 仓库中给store的state属性
...mapState(['num'])
},
//使用methods来访问 store中的方法
methods:{
//调用user模块中的chanegeNickName的方法,并且需要指定确定路径的方法
...mapMutations({
'changeNickName':"changeNickName"
})
}
}
</script>
效果演示
7,modules_type
将所有的modutations中的方法归纳起来。
主模块中index.js文件
//这个文件的作用就是做转状体管理
import Vue from 'vue'
import Vuex from 'vuex'
//导入拆分的state
import state from "./state";
//导入拆分的getters
import getters from "./getters";
//导入拆分的mutaion
// import mutations from "./mutations";
import mutations from "./mutations_type";
//导入拆分的actions
import actions from "./actions";
import modules from "./modules";
//表示使用 vuex
Vue.use(Vuex)
//暴露的第一种方式
export default new Vuex.Store({
//相当于组件中的data,专门用来存放全局的数据,他是一个对象
state,
//getters相当于组件中到的computed,getter是全局的,computed是组件内部使用的
//可以将 computed中的 num(){} 放在getters中统一全局使用
getters,
//mutations相当于组件中的methods,但是他不能使用异步方法(定时器,axios),这个属性存放方法来修改state属性的值
mutations,
//actions属性是专门处理异步请求的,实际修改状态值的是mutations
//action函数 接收一个与store实例具有相同方法的和属性的context对象,因此你可以调用context.commit,提交一个mutation,或者通过
//context.getters 来获取state和 getters。在之后的Moudles被介绍到的时候,你就知道,context对象为什么不是store实例本身了
//简单来说就是有了context对象就可以使用commit
actions,
//这是一个主模块,在这个主模块可以引用 子模块
modules,
})
//暴露的第二种方式
/*
const store=new Vuex.Store({
})
export default store
*/
mutations.js文件
export const MUTATIONS_TYPE={
INCREASE:'increase',
DECREASE:'decrease'
}
export default {
//创建一个方法,来修改state属性的值,参数就是state
//payload是一个形参,如果组件在commit时,有传这个参数过来,就存在,如果没有传参过来,就是undefined
[MUTATIONS_TYPE.INCREASE](state,payoad){
state.num+=payoad ? payoad :1;
},
//创建一个方法来修改状态值
[MUTATIONS_TYPE.DECREASE](state){
state.num--;
}
}
About.vue组件
<template>
<div class="about">
<!-- 直接访问仓库中的getters中的方法 不须要添加 computed-->
<!-- <h1>About页面的数字={{$store.getters.getNum}}</h1>-->
<!--使用映射来获取 getters方法中的方法,必须要添加 computed-->
<h1>About页面的数字={{getNum}}</h1>
<button @click="increase()">Aboute页面的按钮,点击加1</button>
</div>
</template>
<script>
//使用映射导入 vuex中所有的getters都导入过来
import { mapMutations,mapGetters} from 'vuex'
import {MUTATIONS_TYPE} from "../store/mutations_type";
export default {
computed:{
...mapGetters(['getNum'])
},
methods:{
//第一种方式
...mapMutations([MUTATIONS_TYPE.INCREASE])
//第二种方式
// increase() {
// this.$store.commit(MUTATIONS_TYPE.INCREASE)
// }
}
}
</script>