目录
(一) Vuex 概述
Vuex : 是一个专为Vue.js 应用程序开发的状态管理模式, 它采用集中式存储管理应用的所有组件的状态, 并以相应的规则保证状态以一种可预测的方式发生改变.
即: 状态管理对象, 存储管理着一些共享的状态对象(如: 登录令牌token、URL路由地址…), 以供各个组件使用、响应式的修改
Vuex应用的核心是store(仓库), store 基本上就是一个容器对象, 它里面存储管理着可共享的state(状态)
Vuex和全局对象的区别:
- Vuex的状态存储是响应式的, 若 store 中的state状态发生改变, 那么相应的组件也会相应地得到更新
- Vuex 官方不建议直接修改store中的state状态, 改变store中的state状态的唯一途径: commit提交mutation
(二) Vuex 基本使用
1. vuex 安装
通过命令安装vuex依赖, 也可以通过VueCli脚手架安装
npm install vuex --save
2. vuex 基本架构
在src下创建文件: /src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
// 1. 通过Vue.use(插件), 安装插件
Vue.use(Vuex)
// 2.创建Vuex.Store对象并导出, 以供Vue实例使用
export default new Vuex.Store({
// state: Vuex存储的状态共享对象
state: {
count: 100
},
mutations: {
},
actions: {
},
getters: {
},
mudules: {
}
})
Vue实例使用store对象(main.js)
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
store, // Vue实例使用store对象
components: { App },
template: '<App/>'
})
创建两个组件, 分别使用Vuex中state定义的count对象: this.$store.state.count
<template>
<div>
<h3>------------------子组件-----------------</h3>
<p>子组件使用Vuex中state定义的 count: {{$store.state.count}}</p>
</div>
</template>
<script>
export default {
name: 'ChildCmp'
}
</script>
<template>
<div>
<h3>------------------父组件-----------------</h3>
<p>父组件使用Vuex中state定义的 count: {{$store.state.count}}</p>
<child-cmp/>
</div>
</template>
<script>
import ChildCmp from './childCmp'
export default {
name: 'ParentCmp',
components: {
ChildCmp
}
}
</script>
(三) vuex-state
state: Vuex存储的状态对象, Vuex 使用单一状态树, 用一个对象就包含了全部的应用层级状态, 即作为一个唯一数据源而存在, 也意味着, 每个应用将只会有一个store实例
// 在此定义的状态, 状态对象共享给各个组件
state: {
counter: 1,
...
}
mapState: 辅助函数, 在组件中将多个状态定义为计算属性, mapState() 函数返回值是个compute对象
- mapState({}): 函数的参数为对象
import { mapState } from 'vuex' export default { ... , computed: mapState({ // 第一种写法: 计算属性名: function(state) { return ... } counter1 : function(state) { // state: Vuex中state对象 return state.counter * 10 } // 第二种写法: 计算属性名: '字符串参数', 等同于 counter1: state => state.counter counter1: 'counter' }) }
- mapState([]): 函数的参数为数组
import { mapState } from 'vuex' export default { ... , // 计算属性的名称 与 state中对象名称相同 computed: mapState([ 'counter' ]) }
- mapState() 函数 与 组件内计算属性 并存(对象展开运算符)
import { mapState } from 'vuex' export default { ... , data() { return { num: 10 } }, computed: { increment() { return num+++ }, ...mapState({}) } }
(三) vuex-getters
getters: 可以认为是store的计算属性, 对state状态对象进行逻辑计算, 且getters的返回值会根据它的依赖被缓存起来, 只有当它的依赖值发生改变才会被重新计算
export default new Vuex.store({
state: {
counter: 100
},
getters: {
// 默认参数传递state对象和getters对象
powerCounter(state, getters) {
return state.counter * state.counter
},
sumCounter(state) {
// 返回一个函数, 函数存在一个参数num, 函数再返回num+counter
return function(num) {
return state.counter + num
}
}
}
})
<h3>{{$store.getters.powerCounter}}</h3> <!-- 10000 -->
<h3>{{$store.getters.sumCounter(100)}}</h3> <!-- 200 -->
(四) vuex-mutations
Mutation状态更新: 更改Vuex的store中的状态的唯一方法是提交mutation, 且 Mutation 必须是同步函数, 是为让devtools工具可以捕捉mutation的快照, 记录每一次对state的操作. 如果为异步操作, devtools工具无法记录
mutation主要包括两部分:
- 字符串的事件类型(type)
- 一个回调函数(handler), 函数有两个参数: state状态对象 和 payload载荷对象(commit提交时, 传入的额外参数对象)
通过 this.$store.commit(‘事件类型’, payload) 修改Vuex的store中的状态
export default new Vuex.store({
state: {
counter: 100
},
mutations: {
// 事件类型: function(状态对象, 载荷参数) {}
increment: function(state, payload) {
state.counter += payload
},
encrement(state, payload) {
state.counter -= payload.num // 因为下面使用了对象的提交风格
}
}
})
<template>
<div>
<p>{{$store.state.counter}}</p>
<button @click="addition(5)">+5</button>
<button @click="subtraction(10)">-10</button>
</div>
</template>
<script>
export default {
name: 'ParentCmp',
methods: {
addition(num) {
// 通过提交mutation修改Vuex的store中的状态
this.$store.commit('increment', num)
},
subtraction(num) {
// 对象风格的提交方式
this.$store.commit({
type: 'encrement',
num
})
}
}
}
</scritp>
(五) vuex-actions
Action: 类似于Mutation, 用来替代Mutation进行异步操作. Action最终还是只能通过提交mutation来修改状态, 而不是直接变更状态
action主要包括两部分:
- 字符串的事件类型(type)
- 一个回调函数(handler), 函数有两个参数: context状态对象 和 payload载荷对象(dispatch分发时, 传入的额外参数对象)
通过 this.$store.dispatch(‘事件类型’, payload) 分发Action
export default new Vuex.store({
state: {
counter: 100
},
mutations: {
increment: function(state, payload) {
state.counter += payload
},
encrement(state, payload) {
state.counter -= payload.num
}
},
actions: {
// 事件类型: function(状态对象, 载荷参数) {}
asynincrement(context, payload) {
// 模拟异步操作
setTimeout(() => {
// action 内部也是通过提交mutation来修改状态
context.commit('increment', payload)
}, 1000)
}
}
})
<template>
<div>
<p>{{$store.state.counter}}</p>
<button @click="addition(5)">+5</button>
<button @click="subtraction(10)">-10</button>
<button @click="asynAddition(10)">异步 +10</button>
</div>
</template>
<script>
export default {
name: 'ParentCmp',
methods: {
addition(num) {
this.$store.commit('increment', num)
},
subtraction(num) {
this.$store.commit({
type: 'encrement',
num
})
},
asynAddition(num) {
// 通过 this.$store.dispatch('事件类型', payload) 分发Action
this.$store.dispatch('asynincrement', num)
}
}
}
(六) vuex-modules
Vue使用单一状态树, 意味着只存在一个Store实例, 会将所有的状态对象交给一个Store来管理, 当应用变的非常复杂时, Store对象就会变得异常臃肿
Module: Vuex允许将Store分割成 module模块, 每个模块都拥有自己的 state、getters、mutations、actions等. 多个模块, 使用 namespaced命名空间属性来区分
const moduleA = {
namespaced: true, // 使用命名空间属性来区分模块
state: {
name: 'zhangsan' // this.$store.state.moduleA.name 获取
},
gettters: {
/*
state: 当前模块state状态对象
getters: 当前模块getters计算属性
rootState: 根模块state状态对象(也包含了所有子模块state对象)
rootGetters: 根模块rootGetters计算属性(也包含了所有子模块rootGetters计算属性)
*/
nameInfo(state, getters, rootState, rootGetters) {
return sate.name + ' Info' // this.$store.getters['module/nameInfo'] 获取
}
},
mutations: {
updateNameM(state, payload) {
state.name = 'lisi' // this.$store.commit('moduleA/updateNameM') 提交
}
},
actions: {
/*
context: store上下文对象
context: {state, getters, rootState, rootGetters, commit, dispatch}
*/
updateNameA(context, payload) {
setTimeout(() => {
context.commit('updateNameM') // this.$store.dispatch('moduleA/updateNameA') 分发Action
}, 1000)
}
}
}
const moduleB = {
namespaced: true,
state: {...},
getters: {...},
mutations: {...},
actions: {...},
modules: {...}
}
export default new Vux.store({
state: {...},
getters: {...},
mutations: {...},
actions: {...},
modules: {
moduleA,
moduleB,
...
}
})
使用辅助函数绑定带命名空间的模块
import {mapState, mapGetters, mapActions, mapMutations} from 'vuex'
export default {
name: 'ParentCmp',
computed() {
...mapState('moduleA', [
'name',
...
]),
...mapGetters('moduleA', [
'nameInfo',
...
])
},
method() {
...mapMutations('moduleA', [
'updateNameM', // 直接当普通方法使用, 自动提交
...
]),
...mapActions('moduleA', [
'updateNameA', // 直接当普通方法使用, 自动分发
...
])
}
}