Vuex(状态管理)
Vuex 是什么?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex的关键词
1.State 状态
2.Getter 获得者
3.Mutation 变化
4.Action 行动
5.Module 模块
6.store 仓库
7.commit 犯;干;
8.dispatch 派遣
基础用法
页面store/index.js(store配置)
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
//状态
count: 1
},
getters: {
//类似计算机属性
shuxing1: state => {
//state :可以访问数据
return state.count;
}
shuxing2: (state, getters)=> {
//getters:访问其他函数,等同于 store.getters
return getters.shuxing1;
}
},
mutations:{
//改变状态的函数放这里,只能同步
//context.commit('add')或store.commit('add')执行下面函数
add(state) {
// 变更状态
state.count += 2
}
},
actions:{
//可以异步(一般用来解决异步),用context.commit('add')执行mutations里面的add函数
addCountAction (context) {
//在执行累加的时候,会等待两秒才执行
setTimeout(function () {
context.commit('add')
}, 2000)
}
}
})
export default store
页面 main.js (引入全局store)
// 页面路径:main.js
import Vue from 'vue'
import App from './App'
import store from './store'
Vue.prototype.$store = store
// 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
const app = new Vue({
store,
...App
})
app.$mount()
其它页面pages/index/index.vue(获取state)
- 通过属性访问,需要在根节点注入
store
。
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<text>用户名:{{username}}</text>
</view>
</template>
<script>
import store from '@/store/index.js';//需要引入store
export default {
data() {
return {}
},
computed: {
username() {
return store.state.username
}
}
}
</script>
- 在组件中使用,通过
this.$store
访问到state
里的数据。
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<text>用户名:{{username}}</text>
</view>
</template>
<script>
export default {
data() {
return {}
},
computed: {
username() {
return this.$store.state.username
}
}
}
</script>
辅助函数
mapState
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view>用户名:{{username}}</view>
<view>年龄:{{age}}</view>
</view>
</template>
<script>
import { mapState } from 'vuex'//引入mapState
export default {
data() {
return {}
},
computed: mapState({
// 从state中拿到数据 箭头函数可使代码更简练
username: state => state.username,
age: state => state.age,
})
}
</script>
mapGetters
mapGetters
辅助函数仅仅是将 store
中的 getter
映射到局部计算属性:
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view>{{doneTodosCount}}</view>
</view>
</template>
<script>
import {mapGetters} from 'vuex' //引入mapGetters
export default {
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodos',
'doneTodosCount',
// ...
])
}
}
</script>
如果你想将一个 getter
属性另取一个名字,使用对象形式:
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view>{{doneCount}}</view>
</view>
</template>
<script>
import {mapGetters} from 'vuex' //引入mapGetters
export default {
computed: {
...mapGetters({
// 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
}
}
</script>
mapMutations
使用 mapMutations
辅助函数将组件中的 methods
映射为 store.commit
调用。
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view>数量:{{count}}</view>
<button @click="add">增加</button>
</view>
</template>
<script>
import { mapMutations } from 'vuex'//引入mapMutations
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
...mapMutations(['add'])//对象展开运算符直接拿到add
}
}
</script>
mapActions
mapActions
辅助函数将组件的methods
映射为store.dispatch
调用(需要先在根节点注入store
)
<!-- 页面路径:pages/index/index.vue -->
<template>
<view>
<view>数量:{{count }}</view>
<button @click="addCountAction">增加</button>
</view>
</template>
<script>
import { mapActions } from 'vuex'
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
...mapActions([
'addCountAction',
// 将 `this.addCountAction()` 映射为`this.$store.dispatch('addCountAction')`
// 将 `this.addCountAction(amount)` 映射为`this.$store.dispatch('addCountAction', amount)`
])
}
}
</script>
mapActions
也支持传递一个对象:
methods: {
...mapActions({
addCount: 'addCountAction',
// 将 `this.addCount()` 映射为 `this.$store.dispatch('addCountAction')`
})
}
组合 Action
action
通常是异步的,那么如何知道 action
什么时候结束呢?更重要的是,我们如何才能组合多个 action
,以处理更加复杂的异步流程?
首先,你需要明白 store.dispatch
可以处理被触发的 action
的处理函数返回的 Promise
,并且 store.dispatch
仍旧返回 Promise
:
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}
现在你可以在组件中使用:
store.dispatch('actionA').then(() => {
// ...
})
在另外一个 action
中也可以:
actions: {
// ...
actionB ({ dispatch, commit }) {
return dispatch('actionA').then(() => {
commit('someOtherMutation')
})
}
}
最后,如果我们利用 async / await
,我们可以如下组合 action
:
// 假设 getData() 和 getOtherData() 返回的是 Promise
actions: {
async actionA ({ commit }) {
commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
await dispatch('actionA') // 等待 actionA 完成
commit('gotOtherData', await getOtherData())
}
}
一个
store.dispatch
在不同模块中可以触发多个action
函数。在这种情况下,只有当所有触发函数完成后,返回的Promise
才会执行。
Module
Vuex
允许我们将 store
分割成模块(module)。每个模块拥有自己的 state
、mutation
、action
、getter
、甚至是嵌套子模块——从上至下进行同样方式的分割:
- 在
store
文件夹下新建modules
文件夹,并在下面新建moduleA.js
和moduleB.js
文件用来存放vuex
的modules
模块。
├── components # 组件文件夹
└── myButton
└── myButton.vue # myButton组件
├── pages
└── index
└── index.vue # index页面
├── static
├── store
├── index.js # 我们组装模块并导出 store 的地方
└── modules # 模块文件夹
├── moduleA.js # 模块moduleA
└── moduleB.js # 模块moduleB
├── App.vue
├── main.js
├── manifest.json
├── pages.json
└── uni.scss
- 在
main.js
文件中引入store
。
// 页面路径:main.js
import Vue from 'vue'
import App from './App'
import store from './store'
Vue.prototype.$store = store
// 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
const app = new Vue({
store,
...App
})
app.$mount()
- 在项目根目录下,新建
store
文件夹,并在下面新建index.js
文件,作为模块入口,引入各子模块。
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import moduleA from '@/store/modules/moduleA'
import moduleB from '@/store/modules/moduleB'
Vue.use(Vuex)
export default new Vuex.Store({
modules:{
moduleA,moduleB
}
})
- 子模块
moduleA
页面内容。
// 子模块moduleA路径:store/modules/moduleA.js
export default {
state: {
text:"我是moduleA模块下state.text的值"
},
getters: {
},
mutations: {
},
actions: {
}
}
- 子模块
moduleB
页面内容。
// 子模块moduleB路径:store/modules/moduleB.js
export default {
state: {
timestamp: 1608820295//初始时间戳
},
getters: {
timeString(state) {//时间戳转换后的时间
var date = new Date(state.timestamp);
var year = date.getFullYear();
var mon = date.getMonth()+1;
var day = date.getDate();
var hours = date.getHours();
var minu = date.getMinutes();
var sec = date.getSeconds();
var trMon = mon<10 ? '0'+mon : mon
var trDay = day<10 ? '0'+day : day
return year+'-'+trMon+'-'+trDay+" "+hours+":"+minu+":"+sec;
}
},
mutations: {
updateTime(state){//更新当前时间戳
state.timestamp = Date.now()
}
},
actions: {
}
}
- 在页面中引用组件 myButton ,并通过
mapState
读取state
中的初始数据。
<!-- 页面路径:pages/index/index.vue -->
<template>
<view class="content">
<view>{{text}}</view>
<view>时间戳:{{timestamp}}</view>
<view>当前时间:{{timeString}}</view>
<myButton></myButton>
</view>
</template>
<script>
import {mapState,mapGetters} from 'vuex'
export default {
computed: {
...mapState({
text: state => state.moduleA.text,
timestamp: state => state.moduleB.timestamp
}),
...mapGetters([
'timeString'
])
}
}
</script>
- 在组件
myButton
中,通过mutations
操作刷新当前时间。
<!-- 组件路径:components/myButton/myButton.vue -->
<template>
<view>
<button type="default" @click="updateTime">刷新当前时间</button>
</view>
</template>
<script>
import {mapMutations} from 'vuex'
export default {
data() {
return {}
},
methods: {
...mapMutations(['updateTime'])
}
}
</script>
参考链接
https://uniapp.dcloud.net.cn/tutorial/vue-vuex.html#vuex-%E6%98%AF%E4%BB%80%E4%B9%88