赞
踩
最近有小伙伴在vuex这里遇到了些问题,于是我就趁着这个机会来谈一谈我对vuex的理解及用法
根据官网的说法就是:
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
可能有很多小伙伴不是很理解它说的是个啥,WTF? 官方的说明挺抽象的,我一开始也懵逼了!
Vuex其实也并不是很高大上的东西,它是一个公共状态管理库,它在业务非常复杂的时候才会使用
使用场景:
• 多个视图依赖于同一状态。
• 来自不同视图的行为需要变更同一状态。
比如我举个例子,有A和B、C三个组件,是三个一点关系都没有的单独组件,没有嵌套关系,就是兄弟组件,都需要某个值的改变而相应做出一些动作,比如A需要state为true的时候变成红色,B变成蓝色,C变成黑色,当state为false的时候,A变成粉色,B变成绿色,C变成紫色,如果有这么一个需求,就涉及到组件之间的通信了,如果这几个组件是父子关系,那还好说,用props接一下属性就行了,可惜,理想是美好的,现实是骨感的,哈哈,那么就可以考虑使用vuex,下面我们先用vue-cli来搭建一个环境,如何搭建我就不具体说了,如果你用到了vuex,那么你vue肯定也没问题了
这里我再贴一下项目目录结构吧
好了,我们已经跑起项目来了,下面我们先讲讲vuex都有哪些小伙伴吧
前面我们说了,vuex是一个公共状态库,既然是一个公共状态库,怎么会没有状态呢,我们的状态变量肯定有一个盒子来装它,这就是State的作用了,说白了就是相当于Vue里面的data,用来定义变量用的,下面我们看看这个state
首先我们先建一套vuex的代码
首先在assets同级文件夹下新建一个文件夹为store
store下面新建文件index.js ( 先不要问为什么,先跟着新建就对了!),然后新建modules文件夹,这里我习惯用模块的形式来使用vuex,比如购物车模块,这样业务逻辑多的时候,一个模块一个模块的就不会乱了,就写一个shoppingCart.js,这里我们要改变三个组件的颜色,所以写个changeColor.js,如下图所示
import Vue from 'vue';
import Vuex from 'vuex';
import changeColor from './modules/changeColor';
Vue.use(Vuex);
export default new Vuex.Store({
modules:{
changeColor
}
})
const state = { myState:true } const getters = { } const mutations = { } const actions = { } export default{ state, getters, mutations, actions }
vuex写完之后必须要在main.js引入,然后放到你new的那个vue实例里面它才会生效,所以我们做下一步
下面我们去A组件先把咱们在vuex中的State中定义的myState拿到,在A组件的index.js中我们这样写
它是用vue中的计算属性来拿到它的
export default{
data(){
return{
msg:"这是A页面"
}
},
computed:{
state(){
return this.$store.state.changeColor.myState
}
},
mounted(){
console.log(this.$store.state.changeColor.myState);
}
}
在A.vue中我们这样使用
<template>
<div class = "A">
{{msg}}
{{state}}
</div>
</template>
<script src = "./index.js"></script>
<style lang = "scss" scoped src = "./index.scss"></style>
看下结果
我们定义的true已经显示出来了
那么有人会说了,每次都要写一大串this.$store.state.changeColor.myState
,累也累死了,说实话,确实累啊,vuex给我们发了几颗语法糖,我们来看看对应state的语法糖
没错,就是它
我们改造下我们的index.js
// 在单独构建的版本中辅助函数为 Vuex.mapState import { mapState } from 'vuex' export default{ data(){ return{ msg:"这是A页面" } }, computed:mapState({ // 箭头函数可使代码更简练 state: state => state.changeColor.myState, }), mounted(){ console.log(this.$store.state.changeColor.myState); } }
如果你在组件内的变量跟你在vuex中State中的变量名字一样的话,就省事多了,我们来看看
// 在单独构建的版本中辅助函数为 Vuex.mapState import { mapState } from 'vuex' export default{ data(){ return{ msg:"这是A页面" } }, computed:mapState([ // 映射 this.myState 为 store.state.changeColor 'changeColor' ]), mounted(){ console.log(this.$store.state.changeColor.myState); console.log(this.changeColor.myState); } }
如果你没有模块化,就可以直接映射到myState,因为我这里模块化了,只能映射到模块上,然后通过模块拿到状态
又有人问了,你这一整个都把计算属性给占了,那我还玩个屁啊,我在哪还去写其他计算属性?别急,它帮你解决了,这样写
// 在单独构建的版本中辅助函数为 Vuex.mapState import { mapState } from 'vuex' export default{ data(){ return{ msg:"这是A页面" } }, computed:{ ...mapState([ // 映射 this.myState 为 store.state.changeColor 'changeColor' ]), count(){ //其他计算属性 } }, mounted(){ console.log(this.$store.state.changeColor.myState); console.log(this.changeColor.myState); } }
照样能出来
那么state我们就讲完了,下面该讲Getter了
这个getter,就有的说了,我一般大多数是用这个,接下来的例子,我也会用这个getter,对应的vuex的getter是getters
我说的通俗点,getters的作用就是过滤state,就是对state进行特殊处理,来给前面的组件,比如说我们定义了一个myState为true,我们想myState为true的时候,给前面组件的是1,false的时候给前面组件的是0,有人会说,这个功能在组件内部也能写啊,但是,别忘了,这个状态可是一个公共状态,在其它地方也有可能会用的着,这样统一处理的话,会好一点,当然了,在组建内部处理也是可以的,在这里我只是讲一下getter的作用而已,哈哈!
我们把上面举得例子变成真的,调整下代码
const state = { myState:true } const getters = { count:state => state.myState?1:0 } const mutations = { } const actions = { } export default{ state, getters, mutations, actions }
在A.vue中使用一下
computed:{
...mapState([
// 映射 this.myState 为 store.state.changeColor
'changeColor'
]),
count(){
return this.$store.getters.count;
}
},
注意下这里,state是还要通过一层changeColor拿到,getters中的属性不需要这一层了就,直接 this.$store.getters.count就拿到了(具体为什么我也不太清楚,所以我喜欢在实际项目中用这个getters)
语法糖来了,跟getters对应的语法糖是mapGetters
,我们来修改下,我一般习惯跟它的变量名同名,所以我就直接写同名的写法了,这样是最简单的,看下方A组件中的index.js
// 在单独构建的版本中辅助函数为 Vuex.mapState import { mapState,mapGetters } from 'vuex' export default{ data(){ return{ msg:"这是A页面" } }, computed:{ ...mapState([ // 映射 this.myState 为 store.state.changeColor 'changeColor' ]), // count(){ // return this.$store.getters.count; // } ...mapGetters([ 'count' ]) }, mounted(){ console.log(this.$store.state.changeColor.myState); console.log(this.changeColor.myState); console.log(this.$store.getters.count); } }
count还是以花括号插值的形式使用,我们看下结果
还是没变,结果一样
这个函数,说白了就是干嘛的呢,就是改变state中的状态的,但是,很重要的一点,它里面只能写同步代码,但是它有一点特别怪,虽然它是改变state中状态的值的,但是它却不能直接使用,得用actions里面提交一下,我习惯这样,当然我觉得你要使用也没有关系,也能拿到
这个东西对应vuex的代码片段为
下面我们来改变下状态
const state = { myState:true } const getters = { count:state => state.myState?1:0 } const mutations = { toggleState(state){ state.myState = !state.myState; } } const actions = { } export default{ state, getters, mutations, actions }
我们来A.vue中使用这个函数
直接使用语法糖 mapMutations
// 在单独构建的版本中辅助函数为 Vuex.mapState import { mapState,mapGetters,mapMutations } from 'vuex' export default{ data(){ return{ msg:"这是A页面" } }, computed:{ ...mapState([ // 映射 this.myState 为 store.state.changeColor 'changeColor' ]), // count(){ // return this.$store.getters.count; // } ...mapGetters([ 'count' ]) }, methods:{ ...mapMutations([ 'toggleState' // 将 `this.toggleState()` 映射为 `this.$store.commit('toggleState')` ]), changeState(){ this.toggleState(); } }, mounted(){ console.log(this.$store.state.changeColor.myState); console.log(this.changeColor.myState); console.log(this.$store.getters.count); } }
在A.vue中
<template>
<div class = "A">
{{msg}}
{{changeColor.myState}}
{{count}}
<button @click = "changeState()">改变状态</button>
</div>
</template>
<script src = "./index.js"></script>
<style lang = "scss" scoped src = "./index.scss"></style>
下面我们改变下状态,点击按钮
点击之后
是不是很神奇!
鉴于mutations只能写同步代码,如果有异步代码的话,可以放在actions里面进行提交,下一个模块,action
对应vuex的代码块中的
我们这里没有异步代码,所以我们用actions来提交一下我们在mutations定义的toggleState,并在A.vue中来使用一下,我们加段代码
const state = { myState:true } const getters = { count:state => state.myState?1:0 } const mutations = { toggleState(state){ state.myState = !state.myState; } } const actions = { toggleState(context){ context.commit('toggleState'); } } export default{ state, getters, mutations, actions }
我们把toggleState通过actions给提交了,我们去A.vue去使用一下
语法糖 mapActions
,你懂的!
// 在单独构建的版本中辅助函数为 Vuex.mapState import { mapState,mapGetters,mapMutations, mapActions } from 'vuex' export default{ data(){ return{ msg:"这是A页面" } }, computed:{ ...mapState([ // 映射 this.myState 为 store.state.changeColor 'changeColor' ]), // count(){ // return this.$store.getters.count; // } ...mapGetters([ 'count' ]) }, methods:{ // ...mapMutations([ // 'toggleState' // 将 `this.toggleState()` 映射为 `this.$store.commit('toggleState')` // ]), ...mapActions([ 'toggleState', // 将 `this.toggleState()` 映射为 `this.$store.dispatch('toggleState')` ]), changeState(){ this.toggleState(); } }, mounted(){ console.log(this.$store.state.changeColor.myState); console.log(this.changeColor.myState); console.log(this.$store.getters.count); } }
我们继续点击按钮
一样改变了,我个人建议用getters和actions两个就可以了,对了我们总结下,各个代码块对应的语法糖
不过在做实际项目的时候我一般用第2个和第4个,下面我们利用这些,来实现下最初的改变颜色的需求
我先写一些样式
.A{
padding: 30px;
}
.red{
background: red;
}
.pink{
background: pink;
}
.B{
padding: 30px;
}
.blue{
background: blue;
}
.green{
background: green;
}
.C{
padding: 30px;
}
.black{
background: black;
}
.purple{
background: purple;
}
写一下vuex的changeColor.js文件
const state = { myState:true } const getters = { myState:state => state.myState } const mutations = { toggleState(state){ state.myState = !state.myState; } } const actions = { toggleState(context){ context.commit('toggleState'); } } export default{ state, getters, mutations, actions }
在A组件中的index.js中这样写
// 在单独构建的版本中辅助函数为 Vuex.mapState import {mapGetters,mapActions} from 'vuex' export default{ data(){ return{ msg:"这是A页面" } }, computed:{ ...mapGetters([ 'myState' ]) }, methods:{ ...mapActions([ 'toggleState', // 将 `this.toggleState()` 映射为 `this.$store.dispatch('toggleState')` ]), changeState(){ this.toggleState(); } }, mounted(){ } }
A组件中的A.vue
<template>
<div class = "A" :class = "{'red':myState == true,'pink':myState == false}">
{{myState}}
<button @click = "changeState()">改变状态</button>
</div>
</template>
<script src = "./index.js"></script>
<style lang = "scss" scoped src = "./index.scss"></style>
现在的A组件中是这个样子的
我们的目的是在兄弟组件之间通信,所以我们在B组件和C组件里面把myState引进去,还是用语法糖,你懂的
// 在单独构建的版本中辅助函数为 Vuex.mapState import {mapGetters} from 'vuex' export default{ data(){ return{ msg:"这是B页面" } }, computed:{ ...mapGetters([ 'myState' ]) }, methods:{ }, mounted(){ } }
<template>
<div class = "B" :class = "{'blue':myState == true,'green':myState == false}">
{{msg}}
</div>
</template>
<script src = "./index.js"></script>
<style lang = "scss" scoped src = "./index.scss"></style>
我们来看下B组件的样子
我们再把C组件改下,引入myState
// 在单独构建的版本中辅助函数为 Vuex.mapState import {mapGetters} from 'vuex' export default{ data(){ return{ msg:"这是C页面" } }, computed:{ ...mapGetters([ 'myState' ]) }, methods:{ }, mounted(){ } }
<template>
<div class = "C" :class = "{'black':myState == true,'purple':myState == false}">
{{msg}}
</div>
</template>
<script src = "./index.js"></script>
<style lang = "scss" scoped src = "./index.scss"></style>
我们来看下C组件的样子
与我们之前的需求是一致的,当state为true的时候变成红色,B变成蓝色,C变成黑色
现在我们见证奇迹的时刻
我们在A组件里面点击按钮,把myState的状态改变一下,看看其它的组件会不会变,这就实现了兄弟组件之间的通信
点击按钮后
我们看到A组件变成了粉色
我们不做任何操作,直接去看B组件和C组件
ok,这也实现了我们的当初的需求:当state为false的时候,A变成粉色,B变成绿色,C变成紫色
到此为止,vuex就讲完了
可能大家把vuex想的太神秘了,其实也就这么点东西,可能我水平有限,对vuex的理解还没有那么深刻,希望能够帮到大家吧!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。