Vue(5)之 Vuex 状态管理
1、Vuex 状态管理Vuex官网Vuex是一个专门为 Vue.js 应用开发的状态管理模式。它采用集中式储存来管理应用程序中所又组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex也集成到了Vue的官方调试工具vue-devtools中,提供了诸如零配置的time-travel调试、状态快照导入导出等高级调试功能。Vuex的工作原理图:2、表单处理<!DOCTYPE ht
·
- Vue 之 Vuex(1)创建Vuex容器 与 单独JS管理
- Vue 之 Vuex(2)mutation 的使用
- Vue 之 Vuex(3)mapState 的使用
- Vue 之 Vuex(4)Getter 的使用
- Vue 之 Vuex(5)actions 的使用
1、Vuex 状态管理
Vuex
是一个专门为 Vue.js
应用开发的状态管理模式。它采用集中式储存
来管理应用程序中所又组件的状态,并以相应的规则
保证状态以一种可预测
的方式发生变化。Vuex也集成到了Vue的官方调试工具vue-devtools
中,提供了诸如零配置的time-travel调试
、状态快照导入导出
等高级调试功能。
Vuex的工作原理图:
2、表单处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<my-component></my-component>
</div>
<script src="VueJs/vue.js"></script>
<script src="VueJs/vuex.js"></script>
<script>
Vue.component('MyComponent', {
computed: {
...Vuex.mapState([
'message'
])
},
template: `<input type="text" v-model="message">`
})
// 创建Vuex容器
const store = new Vuex.Store({
strict: true,
state: {
message: 'Vue.js 从入门到秃顶'
},
mutations: {
updateMessage(state, msg) {
state.message = msg
}
}
})
new Vue({
el: '#app',
store
})
</script>
</body>
</html>
2.1、如果希望实现双向绑定,可以如下修改:
- 源代码
computed: {
...Vuex.mapState([
'message'
])
},
- 修改后(使用计算属性的
set
方法来提交mutation
)
computed: {
message: {
get() {
return this.$store.state.message
},
set(value) {
this.$store.commit('updateMessage', value)
}
}
}
3、模块
3.1、模块的整体结构
应该有小伙伴注意到这里
state: () => ({ ... })
与之前的写法不太一样,这是因为与 Vue中 data 的情况是一样的,区分局部变量和全局变量。
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
3.2、模块局部
export const moduleA = {
state: () => ({ ... }),
mutations: { .. },
getters: { ... },
actions: { ... },
// 嵌套模块
modules: {
child: {
state: () => ({}),
getters: { ... }
}
}
}
}
3.3、案例
3.3.1、store.js
import Vue from 'vue'
import Vuex from 'vuex'
import {moduleA} from './modules/moduleA'
import {moduleB} from './modules/moduleB'
Vue.use(Vuex)
// 创建Vuex容器
export default new Vuex.Store({
strict: true,
state: {
count: 25
},
modules: {
a: moduleA,
b: moduleB
},
mutations: {
someMutation(state) {
state.count += 29
}
},
getters: {
someOtherGetter(state) {
console.log('root: someOtherGetter')
return state.count * 2
}
},
actions: {
someOtherAction(ctx, payload) {
console.log('root: actions -> someOtherAction' + ctx, payload)
return 'root: actions -> someOtherAction'
},
}
})
3.3.2、moduleA.js
export const moduleA = {
namespaced: true, // 空间命名 即 可以理解为 getters、actions 都带有 moduleA 前缀,支持嵌套。
state: () => ({
// state 写成 方法的样式,即 局部状态
count: 0
}),
mutations: {
increment(state) {
// 这里的 `state` 对象是模块的局部状态
state.count++
},
someMutation(state) {
state.count += 17
}
},
getters: {
someOtherGetter(state) {
console.log('moduleA: someOtherGetter')
return state.count * 2
},
// 对于模块内部的 getter,根节点状态会作为第三个参数(rootState)暴露出来
sumWithRootCount(state, getters, rootState) {
return state.count + rootState.count
},
// 在这个模块的 getter 中,`getters` 被局部化了
// 你可以使用 getter 的第四个参数来调用 `rootGetters`
someGetter(state, getters, rootState, rootGetters) {
// console.log(getters.someOtherGetter) // -> 'moduleA/someOtherGetter'
// console.log(rootGetters.someOtherGetter) // -> 'someOtherGetter'
return 'getters.someOtherGetter: ' + getters.someOtherGetter + '; rootGetters.someOtherGetter: ' + rootGetters.someOtherGetter
},
},
actions: {
// 这里的传递没有顺序,因为{}内参数(state, commit, dispatch, rootState, getters, rootGetters)都是 context 的属性
incrementIfOddOnRootSum({state, commit, rootState}) {
if ((state.count + rootState.count) % 2 === 1) {
commit('increment')
}
},
// 在这个模块中, dispatch 和 commit 也被局部化了
// 他们可以接受 `root` 属性以访问根 dispatch 或 commit
someAction({dispatch, commit, getters, rootGetters}) {
console.log(getters.someGetter) // -> 'moduleA/someGetter'
console.log(rootGetters.someGetter) // -> 'someGetter'
dispatch('someOtherAction') // -> 'moduleA/someOtherAction'
dispatch('someOtherAction', null, {root: true}) // -> 'someOtherAction'
commit('someMutation') // -> 'moduleA/someMutation'
commit('someMutation', null, {root: true}) // -> 'someMutation'
},
someOtherAction(ctx, payload) {
console.log('moduleA: actions -> someOtherAction' + ctx, payload)
return 'moduleA: actions -> someOtherAction'
},
someRootAction: { // -> 'someRootAction'
root: true, // 在带命名空间的模块注册全局 action
handler(namespacedContext, payload) {
console.log('moduleA: 在带命名空间的模块注册全局 action -> someRootAction')
return namespacedContext, payload
}
}
},
// 嵌套模块
modules: {
// 继承父模块的命名空间
myPage: {
state: () => ({}),
getters: {
profile() {
return 'moduleA: 嵌套 profile'
} // -> getters['moduleA/profile']
}
},
// 进一步嵌套命名空间
posts: {
namespaced: true,
state: () => ({}),
getters: {
popular() {
return 'moduleA: 嵌套 posts/popular'
} // -> getters['moduleA/posts/popular']
}
}
}
}
3.3.3、moduleB.js
export const moduleB = {
namespaced: true,
state: () => ({
count: 100
}),
mutations: {
increment(state) {
state.count += 2
}
},
getters: {
someOtherGetter(state) {
console.log('moduleB: someOtherGetter')
return state.count * 2
},
sumWithRootCount(state, getters, rootState) {
return state.count + rootState.count
},
someGetter(state, getters, rootState, rootGetters) {
return 'getters.someOtherGetter: ' + getters.someOtherGetter + '; rootGetters.someOtherGetter: ' + rootGetters.someOtherGetter
},
},
actions: {
incrementIfOddOnRootSum({state, commit, rootState}) {
if ((state.count + rootState.count) % 2 === 1) {
commit('increment')
}
},
someAction({dispatch, commit, getters, rootGetters}) {
console.log(getters.someGetter)
console.log(rootGetters.someGetter)
dispatch('someOtherAction')
dispatch('someOtherAction', null, {root: true})
commit('someMutation')
commit('someMutation', null, {root: true})
},
someOtherAction(ctx, payload) {
console.log('moduleB: actions -> someOtherAction' + ctx, payload)
return 'moduleB: actions -> someOtherAction'
}
},
// 嵌套模块
modules: {
myPage: {
state: () => ({}),
getters: {
profile() {
return 'moduleB: 嵌套 profile'
}
}
},
posts: {
namespaced: true,
state: () => ({}),
getters: {
popular() {
return 'moduleB: 嵌套 posts/popular'
}
}
}
}
}
3.3.4、Vue组件引用
<template>
<div class="hello">
<h3>moduleA</h3>
<table>
<tr><td>count</td><td>: </td><td>{{ count }}</td></tr>
<tr><td>sumWithRootCount</td><td>: </td><td>{{ sumWithRootCount }}</td></tr>
<tr><td>someGetter</td><td>: </td><td>{{ someGetter }}</td></tr>
<tr><td>posts/popular</td><td>: </td><td>{{ popularA }}</td></tr>
<tr><td>someOtherAction</td><td>: </td><td>{{ someOtherAction() }}</td></tr>
</table>
<h3>moduleB</h3>
<table>
<tr><td>countB</td><td>: </td><td>{{ countB }}</td></tr>
<tr><td>sumWithRootCountB</td><td>: </td><td>{{ sumWithRootCountB }}</td></tr>
<tr><td>someGetterB</td><td>: </td><td>{{ someGetterB }}</td></tr>
<tr><td>posts/popular</td><td>: </td><td>{{ popularB }}</td></tr>
<tr><td>someOtherActionB</td><td>: </td><td>{{ someOtherActionB() }}</td></tr>
</table>
<h3>Root</h3>
<table>
<tr><td>someOtherActionRoot</td><td>: </td><td>{{ someOtherActionRoot() }}</td></tr>
<tr><td>someRootAction</td><td>: </td><td>{{ someRootAction() }}</td></tr>
</table>
</div>
</template>
<script>
import {mapActions, mapGetters, mapState} from 'vuex'
export default {
computed: {
...mapState('a', [
'count'
]),
...mapGetters('a', [
'sumWithRootCount',
'someGetter',
'profile',
]),
...mapGetters('a/posts', {
popularA: 'popular'
}),
...mapState('b', {
countB: 'count'
}),
...mapGetters('b', {
sumWithRootCountB: 'sumWithRootCount',
someGetterB: 'someGetter',
profileB: 'profile',
}),
...mapGetters('b/posts', {
popularB: 'popular'
}),
},
methods: {
...mapActions('a', [
'someOtherAction',
]),
...mapActions('b', {
someOtherActionB: 'someOtherAction',
}),
...mapActions([
'someRootAction'
]),
...mapActions({
someOtherActionRoot: 'someOtherAction',
})
}
}
</script>
<style scoped>
</style>
3.3.5、结果
4、Vuex刷新后数据丢失问题
4.1、方法一(本人验证可用)
utils.js
/**
* 深度复制
* @param o 随意类型
* @returns {string|number|boolean|{}|*[]}
*/
export function deepClone(o) {
// 判断如果不是引用类型,直接返回数据即可
if (typeof o === 'string' || typeof o === 'number' || typeof o === 'boolean' || typeof o === 'undefined') {
return o
} else if (Array.isArray(o)) { // 如果是数组,则定义一个新数组,完成复制后返回
// 注意,这里判断数组不能用typeof,因为typeof Array 返回的是object
const _arr = []
o.forEach(item => {
_arr.push(item)
})
return _arr
} else if (typeof o === 'object') {
const _o = {}
for (const key in o) {
_o[key] = deepClone(o[key])
}
return _o
}
}
/**
* 数据持久化,解决Vuex刷新数据丢失问题
* @param self
*/
export function dataPersistence(self) {
// 数据持久化操作
window.addEventListener('beforeunload', () => {
localStorage.setItem('stateInfo', JSON.stringify(self.$store.state))
})
if (localStorage.getItem('stateInfo')) {
self.$store.replaceState(
Object.assign(
{},
self.$store.state,
JSON.parse(localStorage.getItem('stateInfo'))
)
)
}
localStorage.removeItem('stateInfo')
// console.log('持久化:')
// console.log(this.$store.state)
}
使用
<script>
import { dataPersistence } from '@/utils/utils'
export default {
created() {
// 数据持久化
dataPersistence(this)
}
}
</script>
4.2、其他方法(本人未验证)
- https://www.cnblogs.com/enhengenhengNymph/p/13748113.html
更多推荐
已为社区贡献12条内容
所有评论(0)