vuex是什么,引用官网的话来说。Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。通俗来说就相当于一个仓库,把你想要的值存在里面,像组件之间可以用组件的通信进行一些值的拿用,这只限于组件通信之间,而vuex小仓库里面的值在哪里都可以直接拿用。
1.安装
npm install vuex --save
下载之后在main.js里面全局引入并挂载
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
1.1.state
在src目录下创建一个store文件夹,并创建index.js文件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
name:'张三',
aaa:'111'
},
getters: {
},
mutations: {
},
actions: {
}
})
export default store
如果vuex中引入的东西很多,全部写在这个页面就显得很多很乱,也是可以将state,getters,mutations,actions给抽离成单独文件出来。
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state';
import mutations from './mutations';
import actions from './actions';
import getters from './getters';
Vue.use(Vuex)
const options = {
state,
mutations,
actions,
getters,
};
const store = new Vuex.Store(options);
export default store;
当然,也可以不这样处理,但是当项目大起来这样会是的代码更清晰,到这里vuex已经引入成功,我们在项目中直接就可以用,
export default {
name: "App",
created(){
console.log(this.$store.state.name);//张三
}
};
2.mapState
辅助函数
在每次用的时候都是this.$store.state.xxx的调用会显得非常的冗长,为此可以用mapState辅助函数帮助我们生成计算属性,
<script>
import { mapState } from "vuex";
export default {
computed: {
...mapState(['aaa','name']),
},
mounted() {
console.log(this.aaa);//111
console.log(this.name);//张三
},
};
</script>
2.getters
有时候我们会对state里面的值进行一波处理,在不同的条件下输出不同的state,比如在部分页面里需要把上面的state里面的name换成'我叫张三',这时候怎么办,在需要修改的页面一个一个改太复杂,还是在state里面再定义一个新的值?这样代码看起来很乱冗长,那要是name的值在不同的条件又输出“你叫张三”,“他叫张三”,不可能一直加state的吧,这时候就需要用到了getters,能对state的值进行修改判断。
const store = new Vuex.Store({
state: {
aaa: 11,
name:'张三'
},
getters: {
changeName(state){
return `我叫${state.name}`
},
takeName(state,getters){
return `${state.aaa}-${getters.changeName}`
}
},
})
Getter 可以接受 state和getters 来作为其参数,直接处理参数输出,我们通过this.$store.getters.xxxzhi直接就可以用,当然,我们也可以使用辅助函数来使得代码更加简单
created() {
console.log(this.$store.getters.changeName);//我叫张三
console.log(this.$store.getters.takeName);//11-我叫张三
},
2.mapGetters
辅助函数
<script>
import { mapGetters } from "vuex";
export default {
computed: {
...mapGetters(["changeName", "takeName"]),
},
created() {
console.log(this.changeName);//我叫张三
console.log(this.takeName);//11-我叫张三
},
};
</script>
3.mutations
用官网的话来解释getters和mutations的区别就是,getters是有时候我们需要从 store 中的 state 中派生出一些状态,mutations是更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。getters更像是一个对state的状态的一个修饰,而mutations则是变更状态。
const store = new Vuex.Store({
state: {
aaa: 11,
name:'张三'
},
getters: {
changeName(state){
return `我叫${state.name}`
},
takeName(state,getters){
return `${state.aaa}-${getters.changeName}`
}
},
mutations:{
changeAaa(state){
state.aaa++
},
chagName(state,payload){
state.name = payload.newName
}
}
})
mutations把state作为参数,进行修改,也可以传入额外的参数也叫mutation 的载荷(payload),调用mutation的方法需要用store.commit 方法。
created() {
console.log(this.$store.state.aaa);//11
this.$store.commit('changeAaa')
console.log(this.$store.state.aaa);//12
},
2.mapMutations辅助函数
mapMutations不是解析到计算属性里面,而是解析到方法里去,
<script>
import { mapMutations, mapState, mapGetters } from "vuex";
export default {
data() {
return {
myname: "",
};
},
computed: {
...mapState(["name", "aaa"]),
...mapGetters(["changeName", "takeName"]),
},
mounted() {
console.log(this.aaa); //11
this.$store.commit('changeAaa');
console.log(this.aaa); //12
console.log(this.name); //张三
this.chagName({ newName: "李四" });//传入一个参数
console.log(this.name); //李四
},
methods: {
...mapMutations(["changeAaa", "chagName"]),
},
};
</script>
注意一条重要的原则就是要记住 mutation 必须是同步函数。
4.actions
mutation必须是同步函数,在处理异步的时候,我们就需要用到actions。actions类似于mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
const store = new Vuex.Store({
state: {
aaa: 11,
name:'张三'
},
getters: {
changeName(state){
return `我叫${state.name}`
},
takeName(state,getters){
return `${state.aaa}-${getters.changeName}`
}
},
mutations:{
changeAaa(state){
state.aaa++
},
chagName(state,payload){
state.name = payload.newName
}
},
actions:{
makeAction(context){
setTimeout(() => {
context.commit('changeAaa')
}, 1000);
}
}
})
在上面代码中我们用个计数器来进行异步操作,因为Action不能去操作状态,vuex中只有mutation可以去改变状态,所以我们需要去用mutation方法,这里的action会接收一个参数context,通过context.commit('mutation里面的方法')来异步操作mutilation改变状态。
<template>
<div>
<button @click="look">查看</button>
</div>
</template>
<script>
import { mapMutations, mapState, mapGetters } from "vuex";
export default {
computed: {
...mapState(["name", "aaa"]),
...mapGetters(["changeName", "takeName"]),
},
mounted() {
// console.log(this.aaa, 999); //11
// this.$store.commit('changeAaa');
// console.log(this.aaa, 888); //12
// console.log(this.name, 12); //张三
// this.chagName({ newName: "李四" });
// console.log(this.name, 23); //李四
console.log(this.aaa,'没触发action的state的aaa的值')
this.$store.dispatch("makeAction");
},
methods: {
...mapMutations(["changeAaa", "chagName"]),
look() {
console.log(this.aaa, '触发action的state的aaa改变的值');
},
},
};
</script>
action通过this.$store.dispatch方法触发,在mouted里触发方法,异步计数器一秒后提交mutation改变状态。
2.mapActions辅助函数
mapActions和mapMutations一样都是解析到methods中,
const store = new Vuex.Store({
state: {
aaa: 11,
name:'张三'
},
getters: {
changeName(state){
return `我叫${state.name}`
},
takeName(state,getters){
return `${state.aaa}-${getters.changeName}`
}
},
mutations:{
changeAaa(state){
state.aaa++
},
chagName(state,payload){
state.name = payload.newName
},
actionsAaa(state,n){
state.aaa +=n
}
},
actions:{
makeAction(context){
setTimeout(() => {
context.commit('changeAaa')
}, 1000);
},
takeAcion(context,n){
setTimeout(() => {
context.commit('actionsAaa',n)
}, 1000);
}
}
})
在actions中新加一个takeAcion并传入一个参数n,将这个参数n再传给mutations给actionsAaa,再引入mapActions,解析到methods中,和前面的类似。
<template>
<div>
<button @click="look">查看</button>
</div>
</template>
<script>
import { mapMutations, mapState, mapGetters, mapActions } from "vuex";
export default {
computed: {
...mapState(["name", "aaa"]),
...mapGetters(["changeName", "takeName"]),
},
mounted() {
console.log(this.aaa, "没触发action的state的aaa的值");
this.takeAcion(6);
},
methods: {
...mapMutations(["changeAaa", "chagName"]),
...mapActions(["makeAction", "takeAcion"]),
look() {
console.log(this.aaa, "触发action的state的aaa改变的值");
},
},
};
</script>
给解析的takeAcion传入一个参数,异步改变state的aaa的值。
5.Modules
官网的解释。当项目大起来,vuex中的东西很多时,通过module来进行模块的分割十分的有必要的。首先我们在父模块中引入一个子模块modulesA,并在store文件夹下创建一个modulesA文件,
import Vue from 'vue'
import Vuex from 'vuex'
import modulesA from "./modulesA/index";
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
aaa: 11,
name: '张三'
},
getters: {
},
mutations: {
},
actions: {
},
modules: {
modulesA
}
})
export default store
在modulesA文件夹下创建一个index.js文件,
export default {
namespaced:true,//命名空间的模块
state: {
bbb:'模块A的东西'
},
getters: {
bbbGetters(state){
return `模块B${state.bbb}`
}
},
mutations: {
bbbMutations(state,n){
state.bbb = n
}
},
actions: {
bbbAcions(context,n){
setTimeout(() => {
context.commit('bbbMutations',n)
}, 1000);
}
},
modules:{ //可以继续嵌套命名空间
}
}
当然我们也可以将父模块和子模块的state,getters,mutations,actions抽离成单独的文件出来,这里就不做处理了。在页面获取子模块的state的状态值。
<script>
import { mapState } from "vuex";
export default {
computed: {
...mapState({
bbb:state=>state.modulesA.bbb
})
},
mounted() {
console.log(this.$store.state.modulesA.bbb);
},
};
通过$store.state.子模块.state和辅助函数来获取子模块里面的状态。
<script>
import { mapGetters } from "vuex";
export default {
computed: {
...mapGetters({
'bbbGetters':'modulesA/bbbGetters'
})
},
mounted() {
console.log(this.$store.getters['modulesA/bbbGetters']);
console.log(this.bbbGetters);
},
};
</script>
通过$store.getters['modulesA/bbbGetters']和辅助函数来获取子模块里面的状态。这里和之前都有所不同,辅助函数中需要指定为子模块的方法,而不是父模块的那种形式。
使用mutations时,可以使用
this.$store.commit('modulesA/bbbMutations')
来改变state的状态,这是不传参数的方式,如果只需给mutations传入参数即可
this.$store.commit('modulesA/bbbMutations',88)
当然还可以使用辅助函数mapMutations,
<script>
import { mapMutations } from "vuex";
export default {
mounted() {
this.bbbMutations(99)
},
methods: {
...mapMutations({
'bbbMutations':'modulesA/bbbMutations'
}),
},
};
</script>
为异步时候的actions也是同理
<script>
import { mapActions } from "vuex";
export default {
mounted() {
this.$store.dispatch('modulesA/bbbAcions',''参数)
this.bbbAcions('参数')
},
methods: {
...mapActions({
'bbbAcions':'modulesA/bbbAcions'
}),
},
};
</script>
使用 Vuex 并不意味着你需要将所有的状态放入 Vuex。虽然将所有的状态放到 Vuex 会使状态变化更显式和易调试,但也会使代码变得冗长和不直观。如果有些状态严格属于单个组件,最好还是作为组件的局部状态。你应该根据你的应用开发需要进行权衡和确定,所以对于组件之间的通信还是要掌握的。至此,vuex简单的概述完了,其中还有一些知识点啥的rootState,createNamespacedHelpers,subscribe,subscribeAction,模块重用等等没有涉及到,后续慢慢补充。