Vuex

vuex概述

vuex是一个vue的状态管理工具,所谓的状态就是数据,它可以帮助我们管理vue通用的数据(多组件共享的数据)

vuex的常用场景

  • 某个数据在多个组件来使用,比如个人信息
  • 多个组件共同维护一份数据,比如购物车数据

vuex的优势

  • 数据集中化管理,共同维护一份数据
  • 数据响应式变化
  • 操作简洁,vuex提供了一些辅助函数

vuex使用步骤

1
2
graph LR
安装vuex-->新建vuex模块文件-->创建仓库-->在main.js中导入挂载

安装vuex

1
npm i vuex@3

新建vuex模块文件

新建src/store/index.js专门存放vuex

1
2
3
4
5
6
7
8
9
10
11
import Vue from 'vue'
import Vuex from 'vuex'

// 插件安装
Vue.use(Vuex)

// 创建仓库
const store = new Vuex.Store()

// 导出
export default store

创建仓库

1
2
Vue.use(Vuex)
new Vuex.Store()

main.js导入挂载

main.js中导入仓库,挂载到Vue实例上

1
2
3
4
5
6
7
8
9
10
import Vue from 'vue'
import App from './App.vue'
import store from '@/store/index'

Vue.config.productionTip = false

new Vue({
render: h => h(App),
store
}).$mount('#app')

获取仓库

1
2
//其他组件中均可获取仓库对象
this.$store

注意:后续可以在利用vueCli创建项目时,勾选vuex选项,其会自动完成上述步骤

state

提供数据

State提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储,在State对象中可以添加我们要共享的数据

1
2
3
4
5
6
cosnt store = new Vuex.Store({
//state中是所有组件共享的数据
state:{
数据名:数据值
}
})

获取数据

方案一:通过store直接访问

1
2
3
4
5
6
//模板中获取数据
{{ $store.state.数据名 }}
//组件逻辑中
this.$store.state.数据名
//JS模块中
store.state.数据名

方案二:通过辅助函数

利用mapState辅助函数,帮助我们把store中的数据自动映射到组件的计算属性中

1
2
graph LR
导入mapState-->数组方式引入state-->展开运算符映射

导入mapState

1
import{ mapState } from 'Vuex'

数组方式引入state

1
mapState(['数据名'])

展开运算符映射

1
2
3
computed:{
...mapState(["数据名"])//mapState(["数据名"])是一个对象,...表示将对象展开
}

其他组件访问数据

1
{{ 数据名 }}

mutations

mutations基本用法

vuex同样遵循单向数据流,组件中不能直接修改仓库中的数据,因为一旦项目规模比较大,后续数据发生变化,无法清晰确定是哪个组件操作引起的数据变化

state数据的修改只能通过mutations的操作流程来进行

语法

  • 定义mutations对象,对象中存放修改state的方法
1
2
3
4
5
6
7
8
const store = new Vuex.Store({
state:{
数据名:数据值
},
mutations:{
修改数据的逻辑函数,函数的第一个参数是当前store的state属性
}
})
  • 组件中提交调用mutations
1
this.$store.commit("修改逻辑函数名")

mutations传参

提交mutations时是可以传递参数的this.$store.commit("逻辑函数名",参数)

注意:mutations参数有且只能有一个,如果需要多个参数,则包装成一个对象进行传递

辅助函数mapMutations

mapMutations是把位于mutations中的方法提取出来,映射到组件methods

语法

1
2
3
4
5
import {mapMutations} from 'vuex'

methods:{
...mapMutations(["逻辑函数名"])
}

在使用的地方直接使用:{{ 逻辑函数名 }}

actions

actions用于处理异步操作,比如指定一秒钟之后,修改某个数据的值,而mutations必须是同步的

实例:一秒钟之后,修改statecount为666

1
2
3
4
5
6
7
8
9
10
11
12
13
//提供action方法
actions:{
setAsyncCount(contex,num){
setTimeOut(()=>{//这里用setTimeOut模拟异步,实际场景中一般是发送请求
contex.commit("changeCount",num)
},1000)
}
},
mutations:{
changeCount(state,newCount){
state.count = newCount
}
}

组件页面中的调用

1
this.$store.dispatch('setAsyncCount',666)

辅助函数mapActions

辅助函数mapActions是把位于actions中的方法提取出来,映射到methods

1
2
3
methods:{
...mapActions(["函数名"])
}

getters

定义getters

除了state之外,有时我们需要从state中派生出一些状态,这些状态是依赖state的,此时就会用到getters

实例:state中定义了一个list,是1-10的数组,现在需求为在组件中,显示所有大于5的数据

1
2
3
state:{
list:[1,2,3,4,5,6,7,8,9,10]
}
1
2
3
4
5
6
getters:{
//getters函数第一个参数是state,所有的getters函数都必须要有返回值
filterList(state){
return state.list.filter((num)=>num>5)
}
}

访问getters

方法1:通过store访问getters

1
{{ $store.getters.filterList }}

方法2:通过辅助函数mapGetters映射

1
2
3
computed:{
...mapGetters(["filterList"])
}

获取数据:{{ filterList }}

modules

基本语法

由于vuex使用单一状态树,应用的所有状态(数据)会集中到一个比较大的对象,当应用变得非常复杂时,store对象就会变得相当臃肿,vuex就会变得越来越难以维护,此时就需要进行模块拆分,根据具体项目的业务,对状态按模块进行划分

实例语法:将用户信息模块单独划分

新建文件src/store/module/user.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const state = {
userInfo:{
xxx:xx
}
}
const mutations = {}
const actions = {}
const getters = {}
export default{
state,
mutations,
actions,
getters
}

src/stote/index.js中导入对应模块

1
2
3
4
5
6
import user from './moudle/user'
const store = new Vuex.Store({
modules:{
user
}
})

访问模块中的state

尽管已经分模块了,但其实子模块的状态,还是会挂到根级别的state中,属性名就是模块名

方法1:通过store来访问

1
$store.state.模块名.数据名

方法2:通过mapState来映射

子模块的映射需要开启命名空间,即在子模块导出的地方添加一项配置

1
2
3
4
5
6
7
export default{
namespaced: true,
state,
mutations,
actions,
getters
}

子模块的映射语法

1
mapState("模块名",["数据名"])

访问模块中的getters

直接通过模块名访问

1
$store.getters["模块名/数据名"]

通过mapGetters映射

同样需要开启命名空间

子模块的映射语法

1
mapGetters("模块名",["数据名"])

调用模块中的mutations

注意:默认模块中的mutationsactions会被挂载到全局,需要开启命名空间,才会挂载到子模块

通过store调用子模块mutation

1
$store.commit('模块名/mutation函数名',额外参数)

通过mapMutations进行映射

1
mapMutations("模块名",["mutation函数名“])

调用子模块中的action

同样需要预先开启命名空间

通过store调用子模块中的action

1
$store.dispatch("模块名/action里面的函数名",额外参数)

通过mapActions映射

子模块的映射语法

1
mapActions("模块名",["action函数名"])