8.状态管理 vuex
vuex 是一个专门为vue.js应用程序开发的状态管理模式。用于解决大规模单页应用(SPA)中复杂状态管理和组件间通信的问题。
Vuex 采用了集中式存储管理应用的所有组件的状态,并通过一系列严格的规则来确保状态变更的可预测性和可控性。
可以理解为 存储操作 共享数据
8.0.导入vuex
由于 vue2 对应的 是 vuex3 版本, 而 vue3 对应的 是 vuex4 版本, 所以导入时要注意版本
npm install vuex@3 --save
8.1.基本概念
8.1.1.基本对象
vuex中,有默认的五种基本的对象:
8.1.1.1.状态(State)
state:状态(变量)是整个应用的核心数据源,所有的状态都保存在一个单一的、全局可访问的对象中。
这个状态树对所有组件都是可见的,并且是响应式的,当状态发生改变时,依赖它的组件会自动更新。
8.1.1.2.计算值 ( Getters )
getters:对数据获取之前的再次编译,可以理解为state的计算属性。
8.1.1.3.改变( mutations)
mutations:用于同步修改状态值。是唯一改变 state 的途径,每一个 mutation 都是一个纯函数,它接受 state 作为第一个参数,以及一个 payload(载荷)。
所有状态的修改必须通过提交 mutation 来完成,这样可以确保每次状态变更都有迹可循。
8.1.1.4.动作( actions )
actions:异步操作的处理器,它们可以触发 mutations,但不能直接修改 state。
Actions 通常用于处理异步逻辑(如网络请求),然后通过 commit
方法提交 mutation 来改变 state。
在组件中使用是$store.dispath(’ 函数名’)
8.1.1.5.模块 ( modules )
modules:store的子模块,随着应用规模的增长,状态管理可能会变得非常庞大。
Vuex 允许我们将 store 分割成多个模块(Module),每个模块有自己的 state、mutation、action 和 getter,以此来更好地组织和管理状态。。
8.1.2.配置文件
8.1.2.1.配置文件
@/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {},getters: {},mutations: {},actions: {},modules: {}
})
8.1.2.2.main.js
注意这里 导入的不是 vuex 插件 , 而是导入 主配置文件的 store 对象
因为 import 会在最先执行, 先于
Vue.use()
语句之前执行而 stroe对象 要先 导入 vuex , 再 执行
Vue.use(Vuex)
才能得到所以 要在 状态管理器配置文件 中 调用
Vue.use(Vuex)
import Vue from 'vue'
import App from './App.vue'
import router from './router'// 状态管理器
import store from './store'Vue.config.productionTip = falsenew Vue({router,store,render: h => h(App)
}).$mount('#app')
8.1.3.准备测试页面
8.1.3.1.准备MyState.vue
增加新的 /views/MyState.vue
文件
<template><div><h1>MyState</h1></div>
</template>
<script>
export default {name: "MyState"
}
</script>
8.1.3.2.路由中引入
在路由的 index.js 文件中引入文件
import MyState from '@/views/MyState.vue'
8.1.3.3.配置路由
增加路由配置, 在 路由后追加了 :id , :title
{path: '/myState',name: 'myState',component: MyState
}
8.2.测试
8.2.1.State 使用
8.2.1.1.修改state 对象
state: {count: 0,user : {name: '王小二',age : 20,hobby : ['java', 'html', 'vue']}},
8.2.1.2.接值
在 MyState 组件中 , 通过 this.$store.state
对象取值
<template><div><h1>MyState</h1><hr><h2>{{'count : ' + this.$store.state.count }}</h2><h2>{{'user : ' + this.$store.state.user.name }}</h2><h2>{{'hobby : ' + this.$store.state.user.hobby }}</h2></div>
</template>
8.2.2.mutations 使用
8.2.2.1.定义函数
在 mutations 定义函数
mutations: {ADD_COUNT:(state, param)=>{state.count += param;},CHANGE_USER:(state, param)=>{// state.user = param;Object.assign(state.user, param)},},
8.2.2.2.修改State中的值
在 MyState 组件中 , 增加按钮
<button @click="addCount">addCount</button>
对应的处理函数, 在组件中使用$store.commit( ' 函数名 ', params)
。这个和我们组件中的自定义事件类似。
methods: {addCount() {this.$store.commit('ADD_COUNT', 2)}
}
8.2.2.3.修改对象
在 MyState 组件中 , 再增加按钮
<br>
<button @click="editUser">editUser</button>
对应的处理函数
editUser() {this.$store.commit('CHANGE_USER', {name: '李小三' })
}
8.2.3.Getters使用
8.2.3.1. 增加 getters 配置
Getters接收state作为其第一个参数, getters 作为第二个参数
getters: {// 返回字符串msg:(state)=>{return 'hello';},// 返回 state中的信息getUserName:(state)=>{return state.user.name;},// 返回 state 及 getters中的信息sayHi:(state, getters)=>{return getters.msg + ' , ' + state.user.name;}},
8.2.3.2.显示信息
在 MyState 组件中 , 通过 this.$store.getters
对象取值
<template><div><h1>MyState</h1><hr><h2>{{'msg : ' + this.$store.getters.msg }}</h2><h2>{{'user_name : ' + this.$store.getters.getUserName }}</h2><h2>{{'sayHi : ' + this.$store.getters.sayHi }}</h2></div>
</template>
注意这里 state 中的信息变化了, getters 返回信息也 响应变化结果
8.2.4.Actions 使用
8.2.4.1.增加 actions中的异步函数
这里用延时来模拟异步 , 实际项目中这里可能是异步获取数据
再通过 传入参数context 中的 commit函数来调用 mutations中的函数 来修改 state中的数据
actions: {// 异步 增加CountasyncAddCount:(context, param)=>{// 这里用延时来模拟异步setTimeout(()=>{// 通过 commit 来调用 mutations中的函数context.commit('ADD_COUNT', param);}, 1000)},},
8.2.4.2.页面调用
在 MyState 组件中 , 增加按钮
<br><button @click="incrCount">incrCount</button>
按钮 对应的函数 , 通过 this.$store.dispatch()
调用 actions中的函数
incrCount() {this.$store.dispatch('asyncAddCount', 3)
}
8.2.4.3.异步修改对象
注意 这回 直接使用 解构 传入 context中的 commit函数
asyncEitUser:({commit}, param)=>{setTimeout(()=>{commit('CHANGE_USER', param);}, 1000)}
8.2.4.4.调用 异步修改对象
在 MyState 组件中 , 增加按钮
<br>
<button @click="updateUser">updateUser</button>
按钮 对应的函数 , 通过 this.$store.dispatch()
调用 actions中的函数
updateUser() {this.$store.dispatch('asyncEitUser', {name: '赵小四'})
}
8.3.mapXxx 扩展
8.3.1.mapState, mapGetters基本格式
...mapState(["settings"])
是 Vue.js 中结合 Vuex 使用的一个辅助函数语法,
用于从 Vuex store 中映射(或者说解构)全局状态(state, getters)到局部组件的计算属性(computed)。
当我们在组件中这样使用时:
import { mapState } from 'vuex';export default {computed: {...mapState(["属性名"]),}
}
这意味着该组件现在拥有了一个名为 settings
的计算属性,该属性的值直接对应 Vuex store 中的 settings
状态。每当 store 中的 settings
值发生变化时,组件中的 settings
计算属性也将自动更新,从而驱动组件视图的重新渲染。
8.3.2.mapState, mapGetters使用
8.3.2.1.解构导入
在 MyState 组件中 , 解构导入
import { mapState, mapGetters } from 'vuex'
8.3.2.2.扩展取值
在计算属性中 , 通过 … 扩展运算符 来将对象(数组) 转成 多个变量
computed: {// ...mapState({// count: state => state.count,// user: state => state.user// }),// ...mapState({// count: 'count',// user: 'user'// }),...mapState(['count', 'user']),...mapGetters(['msg','getUserName','sayHi']),// ...mapGetters({// msg: 'msg',// getUserName: 'getUserName',// sayHi: 'sayHi'// })},
8.3.2.3.直接取值
在模板中使用
<h2>{{ 'count : ' + count }}</h2>
<h2>{{ 'user : ' + user.name }}</h2>
<h2>{{ 'sayHi : ' + sayHi }}</h2>
8.3.3.mapMutations, mapActions
8.3.3.1.导入
import { mapMutations, mapActions } from 'vuex'
8.3.3.2.修改methods
methods: {...mapMutations({addCount: 'ADD_COUNT',editUser: 'CHANGE_USER'}),...mapActions({incrCount: 'asyncAddCount',updateUser: 'asyncEitUser'})}
8.3.3.3.传参
用以上方式时, 如果对应函数要传入参数, 就要在调用时传入参数
<hr>
<button @click="addCount(2)">addCount</button>
<br>
<button @click="editUser({name: '李小三' })">editUser</button>
<br>
<button @click="incrCount(3)">incrCount</button>
<br>
<button @click="updateUser({name: '赵小四'})">updateUser</button>
8.4.分模块
8.4.1.分拆文件
当 配置信息比较多, 又属性不同的业务组时, 可以将配置文件进行分拆
如 当前配置文件, 分拆成 num.js , info.js
8.4.1.1.num.js
@/store/modules/num.js
const num = {state:{count: 0},mutations:{ADD_COUNT:(state, param)=>{state.count += param;},},actions:{// 异步 增加CountasyncAddCount:(context, param)=>{// 这里用延时来模拟异步setTimeout(()=>{// 通过 commit 来调用 mutations中的函数context.commit('ADD_COUNT', param);}, 1000)},},
}export default num
8.4.1.2.info.js
@/store/modules/info.js
const info = {state:{user : {name: '王小二',hobby : ['java', 'html', 'vue']}},getters:{// 返回 state中的信息getUserName:(state)=>{return state.user.name;},},mutations:{CHANGE_USER:(state, param)=>{// state.user = param;Object.assign(state.user, param)},},actions:{asyncEitUser:({commit}, param)=>{setTimeout(()=>{commit('CHANGE_USER', param);}, 1000)}},
}export default info
8.4.1.3.getters.js
@/store/getters.js
const getters = {// 返回字符串msg:(state)=>{return 'hello';},// 返回 state 及 getters中的信息sayHi:(state, getters)=>{return getters.msg + ' , ' + state.user.name;}
}
export default getters
8.4.1.4.主配置文件
这样原来的配置文件可以修改成
import Vue from 'vue'
import Vuex from 'vuex'import num from './modules/num'
import info from './modules/info'
import getters from './getters'Vue.use(Vuex)export default new Vuex.Store({modules: {num,info},getters
})
8.4.2.直接调用$store
取 state的值 , 要增加 模块名
<h2>{{'count : ' + this.$store.state.num.count }}</h2>
<h2>{{'user : ' + this.$store.state.info.user.name }}</h2>
<h2>{{'hobby : ' + this.$store.state.info.user.hobby }}</h2>
但 调用 getters, mutations , actions 中的函数, 可以直接调用, 不用调整
8.4.3.mapState, mapGetters
8.4.3.1.mapState导组件
修改代码, 直接导入组件
...mapState(['num','info']),
取值
<h2>{{ 'count : ' + num.count }}</h2>
<h2>{{ 'user : ' + info.user.name }}</h2>
8.4.3.2.mapGetters 导组件
修改代码, 直接导入组件
...mapGetters(['info']),
取值, 无变化
<h2>{{'user_name : ' + this.$store.getters.getUserName }}</h2>
8.4.3.2.***使用命名空间
在 num.js , info.js 文件中加入 namespaced:true,
属性, 这样就为组件 分别命名,
修改 导入, 前面为 对应的 命名,
...mapState("num", ['count']),
...mapState("info", ['user']),
前面为 对应的 命名,与配置文件中对应 , 后面为导入 的变量 , 所以显示修改为直接使用变量
<h2>{{ 'count : ' + count }}</h2>
<h2>{{ 'user : ' + user.name }}</h2>
要注意 这时 getters 的 取值方式 发生变化
<h2>{{'user_name : ' + this.$store.getters["info/getUserName"] }}</h2>
而 动作调用
addCount() {this.$store.commit('num/ADD_COUNT', 2)
},
editUser() {this.$store.commit('info/CHANGE_USER',{name: '李小三' })
},
incrCount() {this.$store.dispatch('num/asyncAddCount', 3)
},
updateUser() {this.$store.dispatch('info/asyncEitUser', {name: '赵小四'})
},
8.4.4.mapMutations, mapActions
当 namespaced:true,
属性,这时使用 mapMutations, mapActions
就变成
...mapMutations("num",{addCount: 'ADD_COUNT',
}),
...mapMutations("info",{editUser: 'CHANGE_USER'
}),
...mapActions("num",{incrCount: 'asyncAddCount',
}),
...mapActions("info",{updateUser: 'asyncEitUser'
})
8.4.5.getters.js
将 分拆出的 getters.js 内容
修改 getters.js , 使用不同 模块的 state 数据时 , 增加所属模块名
const getters = {// 返回字符串msg:(state)=>{return 'hello';},// 返回 state 及 getters中的信息sayHi:(state, getters)=>{return getters.msg + ' , ' + state.info.user.name;}
}
export default getters