"Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化"。这句话是截取vuex官网上对vuex介绍的一句话,对于很多新手朋友,刚接触vuex的时候,肯定被它这么多的专业词汇搞得一脸懵逼,不知所云。那么作为新手该如何学习vuex呢,我的建议就是“理解”,用通俗易懂的话和比喻来说明vuex是个干啥的,是个什么东西。
vuex
上面的前言,说了要用通俗易懂的话来介绍vuex,那么该怎么理解呢?我的理解就是,你把vuex当成一个项目顶层的全局对象来看待,有了这样的认识,你在学习vuex肯定会事半功倍的。
安装vuex
首先我们要安装:
`
npm install vuex --save
`
其次就是创建vuex,创建这一块建议大家按照官方的文档命名来,这样做的目的吗,显而易见,大家都知道开发当中有一些潜在的规范,遵守这些规范就是为了让大家好理解,我这里是干嘛的。在这里我就建议大家在项目里单独创建一个store
的文件夹,并在里面创建一个index.js
的文件吧,然后在index.js
里引入vuex:
`
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(vuex);
// 这个是store文件夹下的index.js文件
export default new Vuex.Store({ // 导出这个对象
state: {
},
getters: {
},
mutations: {
},
actions: {
}
})
`
最后在main.js
的文件里引入我们刚创建的store
文件夹里的index.js
文件:
`
import Vue from 'vue';
import App from './App';
import router from './router';
import store from './store/index'; // 引入vuex
new Vue({
el: '#app',
router,
store, // 注入vuex
components: { App },
template: '<App/>'
})
`
到这一步,我们的vuex就算是搭建完毕了,下面我们就针对vuex里的各个功能模块进行探讨,vuex下面有四个功能模块state, getters, mutations, actions
,也就是四个子对象。
State
前面我们说了vuex其实就是一个全局对象,而这个对象呢包含有四个子对象,子对象一:state
,state
是干嘛的呢?,state
就是这个全局对象专门用来存储数据的地方,也就是公共的数据源:
`
export default new Vuex.Store({
state: { // 这里是存储数据的地方,公共的数据源
animals: [{num: 1, animal: '老虎'}, {num: 2, animal: '狮子'},
{num: 3, animal: '大象'}]
}
})
`
那么如何使用这个数据呢?使用很简单,直接在vue里的computed
对象里书写即可:
`
// 组建里调用
<template>
<div>
<ul>
<li v-for="(item,index) in animals" :key="index">
<label>{{item.num}}</label>
<span>{{item.animal}}</span>
</li>
</ul>
</div>
</template>
// ...其他代码省略
computed: {
animals () {
return this.$store.state.animals;
}
}
`
注意:this.$store
就是我们整个vuex实例,也就是我们说的那个全局对象,state
就是存储公共数据的容器。
这样我们就成功的使用到了vuex state
里的数据了。
Getter
子对象二:getter
,它的功能和作用就类似于vue里的computed
,也就是说vuex里的计算属性,vue里的computed
是用来对数据进行额外操作的,vuex里的getter
也是一样的:
`
export default new Vuex.Store({
state: { // 这里是存储数据的地方,公共的数据源
animals: [{num: 1, animal: '老虎'}, {num: 2, animal: '狮子'},
{num: 3, animal: '大象'}]
},
getter: {
filterAnimal: state => { // 这是个方法
return state.animals.filter(item => {
return item.num > 1
})
}
}
})
`
注意:getter
里面filterAnimal
是个方法,方法名字随你自己定义,state
这个参数就是vuex存储数据里的state
,getter
里所有的方法都默认传入了该参数。
使用也是直接在vue里的computed
对象里书写:
`
// 组建里调用
<template>
<div>
<ul>
<li v-for="(item,index) in filterAnimal" :key="index">
<label>{{item.num}}</label>
<span>{{item.animal}}</span>
</li>
</ul>
</div>
</template>
// ...其他代码省略
computed: {
filterAnimal () {
return this.$store.getters.filterAnimal;
}
}
`
Mutations
子对象三:mutations
,官网里是这样介绍的:“更改 Vuex 的 store 中的状态的 唯一 方法是提交 mutation
”,在这段话里面请大家注意那个“唯一”。这也就是说,对vuexstate
里面的数据,你要想进行修改,必须通过mutations
方式才可以,只有mutations
这个对象里的方法才可以修改state
里的数据,也就是状态:
`
export default new Vuex.Store({
state: { // 这里是存储数据的地方,公共的数据源
animals: [{num: 1, animal: '老虎'}, {num: 2, animal: '狮子'},
{num: 3, animal: '大象'}]
},
mutations: {
addAnimal (state, params) { // params是来自你调用这个方法时传入的参数
state.animals.push(params)
}
}
})
`
注意:mutations
里定义的方法可以接收两个参数,state
就是数据对象,params
就是调用时传递过来的数据
组建里调用mutations
里的方法,使用this.$store.commit()
触发,参数一是你要触发的mutations
里的哪个方法,参数二就是你要传递过去的数据:
`
// 组建里调用
<template>
<div>
<button @click="addAnimal()">增加动物</button>
<ul>
<li v-for="(item,index) in filterAnimal" :key="index">
<label>{{item.num}}</label>
<span>{{item.animal}}</span>
</li>
</ul>
</div>
</template>
// ...其他代码省略
methods: {
addAnimal () {
let animal = {num: 4, animal: '熊猫'}
this.$store.commit('addAnimal', animal);
}
}
`
mutations
操作注意事项:mutations
属于同步操作,所以你在操作时请记得提前声明好你要操作的数据,也就是state
里的数据。
Actions
子对象四:actions
类似于mutations
,actions
的不同点有两点:
action
提交的是mutation
,而不是直接变更状态;action
可以包含任意异步操作;
大家请记住上面这两点,上面介绍mutations
时说过,要想改变state
里面的数据,唯一的方法就是通过mutations
,所以action
这里也是通过mutation
:
`
export default new Vuex.Store({
state: { // 这里是存储数据的地方,公共的数据源
animals: []
},
mutations: {
initAnimal (state, params) { // 初始化state里animals数据
state.animals = params;
}
},
actions: {
initAnimals (context) {
return new Promise((resolve, reject) => {
let animals = [{num: 1, animal: '老虎'}, {num: 2, animal: '狮子'},
{num: 3, animal: '大象'}]
context.commit('initAnimal', animals); //调用mutations里的方法
resolve(animals);
})
}
}
})
`
组建里面调用,使用vuex里的this.$store.dispatch()
方法执行,上面例子中的Promise
并没有实际意义,只是为了演示特意写出来的,你方法体里直接写context.commit()
也是可以的:
`
// 组建里调用
// ...其他代码省略
created() {
this.$store.dispatch('initAnimals');
}
` 在本示例中,调用是在组建生命周期钩子函数里调用,具体在什么地方调用,根据实际的业务需求去实现即可。
mapState、mapGetters、mapActions
mapState、mapGetters、mapActions
这三个是vuex里简化调用而提供的方法,你如果需要使用,需要在你使用的组建单独引入这三个方法:
`
// 组建里调用
<template>
<div>
<ul>
<li v-for="(item,index) in animals" :key="index">
<label>{{item.num}}</label>
<span>{{item.animal}}</span>
</li>
</ul>
</div>
</template>
// ...其他代码省略
import {mapState, mapGetters, mapActions} from 'vuex';
computed: {
// 使用扩展运算符
...mapState({
animals:state => state.animals
}),
}
`
这里暂且只示例mapState
了,其他留给大家自己尝试,稍微说明应用的地方,mapGetters
一般也是在computed
里调用,mapActions
一般是在methods
的方法里调用。
Module
看完上面的内容,其实大家已经会使用vuex了,那么这个Module
是干嘛的呢,上面我们说过,vuex是老顶层的全局对象,如果所有的数据状态如果都写在这个index的文件里面,代码体会越来越大,所以,vuex允许我们把store
分割成各自独立的模块,每个独立模块都有自己的state, getters, mutations, actions
,注意哦,分割出去的各个模块,他们的state
里的数据都是独立,各自是各自的。:
`
import Vue from 'vue';
import Vuex from 'vuex';
import module1 from './modules/module1';
import module2 from './modules/module2';
// 这个是vuex的主模块,也就是index.js这个文件
export default new Vuex.Store({
state,
mutations,
actions,
modules: {
module1,
module2
}
}) `
独立出去的模块使用import
引入进来,在主模块里在modules
里注入即可。
总结
在本篇文章的思路里,是以全局对象的思维方式来学习vuex,其目的也是为了让大家更快速的理解和认识vuex,那么vuex是否就是全局对象呢,在vuex的官方文档里就已经给出了答案和解释:
- Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
- 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
vuex的主要应用就是对多组建或者多页面使用同一个数据源,也就是说共用同一个数据,当我们在某一个组建改变这个数据的某一个状态或者值时,相应的也让其他组建和页面发生相同的变化。 最后也把vuex官网的链接贴在这里,大家看完后可以在去官网查看实际API。