vuex教程(详细)附带demo
vuex是一个专门为vue.js设计的集中式状态管理架构。状态?我把它理解为在data中的属性需要共享给其他vue组件使用的部分,就叫做状态。简单的说就是data中需要共用的属性。(就是一种向各个组件可以传参的方式)1.准备用脚手架搭建一个项目安装vuexnpm install vuex –save新建文件夹store,并在此文件夹下新建store.js文件。项目目录,
vuex是一个专门为vue.js设计的集中式状态管理架构。状态?我把它理解为在data中的属性需要共享给其他vue组件使用的部分,就叫做状态。简单的说就是data中需要共用的属性。
(就是一种向各个组件可以传参的方式)
1. 准备
用脚手架搭建一个项目
安装vuex
npm install vuex --save
新建文件夹store,并在此文件夹下新建store.js文件。项目目录,如下:
- main.js添加
//引入vuex文件
import store from './store/store.js'//注意文件路径
- store文件夹下的store.js
//引入我们的vue和vuex。
import Vue from 'vue'
import Vuex from 'vuex'
//使用我们vuex,引入之后用Vue.use进行引用
Vue.use(Vuex);
2.开始demo
准备工作完成后,我们只使用helloworld.vue和store.js文件
- 在helloworld.vue文件中,直接更改
<template>
<div>
<h2>{{msg}}</h2>
<hr/>
<h3>{{$store.state.count}}</h3>
<div>
<button @click="$store.commit('add')">+</button>
<button @click="$store.commit('reduce')">-</button>
</div>
</div>
</template>
<script>
export default{
data(){
return{
msg:'Hello Vuex',
}
}
}
</script>
2.store.js文件中添加
const state = {
count:1
}
const mutations={
add(state){
state.count+=1;
},
reduce(state){
state.count-=1;
}
}
export default new Vuex.Store({
state,mutations
});
完成页面,点击按钮可以+1或-1
3. state访问状态对象
学习状态对象赋值给内部对象,也就是把stroe.js中的值,赋值给我们模板里data中的值。
- 通过computed的计算属性直接赋值
<h3>{{count}}</h3>
computed:{
count(){
return this.$store.state.count;
}
},
这里需要注意的是 return this.$store.state.count这一句,一定要this,要不你会找不到$store的.
- 通过mapState的对象/数组来赋值
<h3>{{count}}</h3>
<h3>{{countAlias}}</h3>
<h3>{{countPlusLocalState}}</h3>
import {mapState} from 'vuex';//用import引入mapState。
computed: mapState({
// 箭头函数可使代码更简练
count: state => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.msg
}
})
当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组。
computed:mapState(["count"])
4. getters计算过滤操作
getters从表面是获得的意思,可以把他看作在获取数据之前进行的一种再编辑,相当于对数据的一个过滤和加工。你可以把它看作store.js的计算属性。
比如我们现在要对store.js文件中的count进行一个计算属性的操作,就是在它输出前,给它加上100.我们首先要在store.js里用const声明我们的getters属性。
//store.js
getters: {
getcount: state => {
return state.count += 100;
}
}
- 直接获取
<h3>{{$store.getters.getcount}}</h3>
- 通过computed的计算属性直接赋值
<h3>{{count}}</h3>
computed: {
count() {
return this.$store.getters.getcount;
}
}
- 通过mapGetters 的对象/数组来赋值
<h3>{{getcount}}</h3>
import { mapGetters } from 'vuex';
computed: mapGetters(['getcount'])
如果你想将一个 getter 属性另取一个名字,使用对象形式
<h3>{{count}}</h3>
import { mapGetters } from 'vuex';
computed: mapGetters({
// 把 `this.count` 映射为 `this.$store.getters.getcount`
count: "getcount"
})
需要注意的是,你写了这个配置后,在每次count 的值发生变化的时候,都会进行加100的操作。
- mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:
computed:{
...mapGetters(["getcount"])
}
5.Mutation修改状态
他是同步事务.
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
前面我们已经用到过了
2.开始demo
- 提交载荷(Payload)
你可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload):
现在store.js文件里给add方法加上一个参数n。
//store.js
const mutations={
add(state,n){
state.count+=n;
},
reduce(state){
state.count-=1;
}
}
<button @click="$store.commit('add',10)">+10</button>
<button @click="$store.commit('reduce')">-1</button>
- 模板获取Mutations方法
实际开发中我们也不喜欢看到$store.commit( )这样的方法出现,我们希望跟调用模板里的方法一样调用。
例如:@click=”reduce” 就和没引用vuex插件一样。
在helloworld.vue上进行如下更改
<button @click="add(10)">+10</button>
<button @click="reduce">-1</button>
import { mapMutations } from 'vuex';
methods:mapMutations([
'add','reduce'
]),
或者这么写,也可以
<button @click="add10(10)">+10</button>
<button @click="reduce1">-1</button>
methods:{
...mapMutations({
add10: 'add' ,// 将this.add10() 映射为 this.$store.commit('add')
reduce1:'reduce'//其实就是方法又命名了一下
})
},
第二个参数可以是对象
<button @click="$store.commit('reduce',{type:'reduce',nums:'2'})">-</button>
reduce(state, payload) {
state.count -= payload.nums
},
6.actions异步修改状态
actions是异步的改变state状态,而Mutations是同步改变状态
在actions里写了两个方法addAction和reduceAction,在方法体里,我们都用commit调用了Mutations里边的方法。
context:上下文对象,这里你可以理解称store本身。
{commit}:直接把commit对象传递过来,可以让方法体逻辑和代码更清晰明了。
- 方法调用
<button @click="$store.dispatch('addAction')">+</button>
<button @click="$store.dispatch('reduceAction')">-</button>
mutations: {
add(state) {
state.count += 1
},
reduce(state) {
state.count -= 1
},
},
actions: {
addAction(context) {
context.commit('add')
},
reduceAction({ commit }) {
commit('reduce')
},
},
- 带参数调用
<button @click="$store.dispatch('addAction',5)">+</button>
mutations: {
add(state, n) {
state.count += n
},
},
actions: {
addAction(context, n) {
context.commit('add', n)
},
},
// 以载荷形式分发
store.dispatch('add', {
amount: 10
})
// 以对象形式分发
store.dispatch({
type: 'add',
amount: 10
})
- mapActions 辅助函数
<button @click="addAction">+</button>
<button @click="reduceAction">-</button>
import { mapActions } from "vuex";
methods: mapActions(["addAction", "reduceAction"])
//
methods: {
...mapActions(["addAction", "reduceAction"])
}
<button @click="add">+</button>
<button @click="reduce">-</button>
import { mapActions } from "vuex";
methods: mapActions({ add: "addAction", reduce: "reduceAction" })
//
methods: {
...mapActions({ add: "addAction", reduce: "reduceAction" })
}
- 异步
action与mutations主要区别在于 异步操作的顺序执行问题,当A方法必须依赖于B方法执行的结果时
为什么要用Action管理异步操作
举个例子
<template>
<div>
<h3>{{count}}</h3>
<div>
<button @click="add">+</button>
<button @click="reduce">-</button>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from "vuex";
export default {
computed: {
...mapState(["count"])
},
methods: {
...mapActions({ add: "addAction", reduce: "reduceAction" })
}
};
</script>
export default new Vuex.Store({
state: {
count: 1
},
mutations: {
add(state) {
state.count += 10
},
reduce(state) {
state.count -= 1
},
},
actions: {
addAction({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('add')
resolve()
}, 3000)
})
},
reduceAction({ dispatch, commit }) {
return dispatch('addAction').then(() => {
commit('reduce')
})
}
},
})
异步操作,此代码执行后,
reduceAction方法需先执行addAction
点击减号,等待3秒,count = 10,先执行addAction,在执行reduceAction.(1+10-1)
点击加号,紧接着点击减号,先变成11,紧接着变成20,先执行addAction,在执行addAction,reduceAction.(1+10 +10-1)
- action 结合 async / await 例子
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
function getnumber(fun) {
return new Promise((resolve, reject) => {
setTimeout(() => {
fun('setCount', 100)
resolve()
}, 1000)
})
}
export default new Vuex.Store({
state: {
count: 1
},
mutations: {
add(state) {
state.count += 10
},
reduce(state) {
state.count -= 1
},
setCount(state, data) {
state.count = data
},
},
actions: {
async addAction({ commit }) {
commit('add', await getnumber(commit)) //先异步请求数据,在执行add
},
async reduceAction({ dispatch, commit }) {
await dispatch('addAction') // 等待 addAction 完成
commit('reduce', await getnumber(commit)) //先异步请求数据,在执行reduce
}
// 同上
// async addAction({ commit }) {
// commit('add', await new Promise((resolve, reject) => {
// setTimeout(() => {
// commit('setCount', 10)
// resolve()
// }, 1000)
// })) //先异步请求数据,在执行add
// },
// async reduceAction({ dispatch, commit }) {
// await dispatch('addAction') // 等待 addAction 完成
// commit('reduce', await new Promise((resolve, reject) => {
// setTimeout(() => {
// commit('setCount', 10)
// resolve()
// }, 1000)
// })) //先异步请求数据,在执行reduce
// }
},
})
调用 addAction 方法 , 执行 setCount ->add
调用 reduceAction方法 , 执行 addAction(setCount ->add)->setCount ->reduce
7.module模块组
随着项目的复杂性增加,我们共享的状态越来越多,这时候我们就需要把我们状态的各种操作进行一个分组,分组后再进行按组编写。
代码如图所示
vue文件调用
<h1>moduleA:{{$store.state.moduleA.count}}</h1>
<h1>moduleB:{{$store.state.moduleB.count}}</h1>
重命名
export default new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
调用时,将对应的名称更改即可
computed调用
computed: {
a(){
return this.$store.state.a.count
}
},
//mapState
computed: mapState({
a: state => state.a.count,
//a: ({ a }) => a.count
b(state) {
return state.b.count;
}
}),
在模块中,state 是被限制到模块的命名空间下,需要命名空间才能访问。 但actions ,mutations 和 getters 却没有被限制,在默认情况下,它们是注册到全局命名空间下的,所谓的注册到全局命名空间下,其实就是我们访问它们的方式和原来没有module 的时候是一样的。
命名空间
demo(包含mapState, mapMutations, mapActions, mapGetters相关使用)
const moduleA = {
namespaced: true,//命名空间
state: {
count: 1
},
mutations: {
add(state, n) {
state.count += n
},
reduce(state, n) {
state.count -= n
},
},
getters: {
getcount: state => {
return state.count += 100;
}
},
actions: {
addAction(context, n) {
context.commit('add', n)
},
reduceAction({ commit }, n) {
commit('reduce', n)
},
}
}
export default moduleA
<template>
<div>
mapState
<h1>{{count}}</h1>
<h1>{{$store.state.a.count}}</h1>
mapGetters
<h1>{{getcount}}</h1>
<h1>{{$store.state.getcount}}</h1>
mapMutations
<button @click="add(10)">+</button>
<button @click="reduce(5)">-</button>
<br>
<button @click="aaa">+</button>
<button @click="bbb">-</button>
<br>
mapActions
<button @click="addAction(10)">+</button>
<button @click="reduceAction(5)">-</button>
<br>
<button @click="ccc">+</button>
<button @click="ddd">-</button>
<br>
<div></div>
</div>
</template>
<script>
import { mapState, mapMutations, mapActions, mapGetters } from "vuex";
export default {
computed: {
// ...mapState("a", {
// count: "count",
// count: state => state.count,
// count(state) {
// return state.count;
// }
// }),
...mapState("a", ["count"]),
//---------------------------------------------
// ...mapGetters("a", {
// getcount : "getcount"
// })
...mapGetters("a", ["getcount"])
},
methods: {
// ...mapMutations("a", {
// add: "add",
// reduce: "reduce"
// }),
...mapMutations("a", ["add", "reduce"]),
aaa() {
this.$store.commit("a/add", 10);
// this.add(10);
},
bbb() {
// this.$store.commit('a/reduce',5);
this.reduce(5);
},
//---------------------------------------
// ...mapActions("a", {
// addAction: "addAction",
// reduceAction: "reduceAction"
// }),
...mapActions("a", ["addAction", "reduceAction"]),
ccc() {
this.$store.dispatch("a/addAction", 10);
// this.add(10);
},
ddd() {
// this.$store.dispatch('a/reduceAction',5);
this.reduce(5);
}
}
};
</script>
根store
那么怎样才能获取到根store 中的state 和 getters 呢? Vuex 提供了 rootState, rootGetters 作为module 中 getters 中默认参数, actions中context 对象,也会多了两个属性,context.getters, context. rootState, 这些全局的默认参数,都排在局部参数的后面。
更多推荐
所有评论(0)