目录
专门在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 vue 应 用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
原理图:
State | VuexVue.js 的中心化状态管理方案
https://vuex.vuejs.org/zh/guide/state.html
vuex多应用于多个组件应用与同一个状态,多个组件变更同一状态。
什么是“状态管理模式”?
这个状态自管理应用包含以下几个部分:
- 状态,驱动应用的数据源;
- 视图,以声明方式将状态映射到视图;
- 操作,响应在视图上的用户输入导致的状态变化。
以下是一个表示“单向数据流”理念的简单示意:
但是,当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
npm i vuex@3 注释:@3是版本号,vue2用vuex@3版本,vue3用4版本
概念:每一个Vuex应用的核心就是Store(仓库),我们可以说Store是一个容器,它包含着你的应用中大部分的状态 (state)。但Store里面的状态与单纯的全局变量是不一样的,无法直接改变Store中的状态。想要改变状态需通过mutation去修改。
Vuex 和单纯的全局对象有以下两点不同:
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
创建文件夹store与src根目录下,建立index.js。需包含actions,mutations,state结构如下:
import Vue from 'vue' // 引入vue
import Vuex from 'vuex' // 引入vuex
Vue.use(Vuex) // 应用vue插件
// actions响应组件中的动作
const actions = { }
// mutations操作数据state
const mutations = { }
// 准备state存储数据
const state = {
//状态对象
}
//想要对状态有要进一步的加工时可以用到
//getters 从 store 中的 state 中派生出一些状态
const getters={
randmajor(state){
return state.major+Math.ceil(Math.random()*9) + Math.ceil(Math.random()*9) + Math.ceil(Math.random()*9);
}
}
// 创建store并导出
const store = new Vuex.Store({
actions,
mutations,
state,
getters
})
//默认导出store
export default store
在main.js中引入store,全局组件都可以使用vuex。
import store from './store'
new Vue({
render: h => h(App),
store,
}).$mount('#app')
state是状态数据,可以通过this.$store.state来直接获取状态,也可以利用vuex提供的mapState辅助函数将state映射到计算属性(computed)中去。
示例:
1. index.js
const state = {
//状态对象
name:'2209',
major:'web前端',
}
2. 两个组件中的写法
1)插值引用:{{$store.state.name}}
班级:{{$store.state.name}},专业:{{$store.state.major}}
2)在计算属性中写法
班级:{{name}},专业:{{major}}
computed:{
name(){
return this.$store.state.name;
},
major(){
return this.$store.state.major;
}
}
3)数据映射写法
班级:{{myname}},专业:{{mymajor}}
import {mapState} from 'vuex'
computed:{
// 当计算属性的名称与vuex一致的时候 用数组形式
// ...mapState(["name","major"]),
// 当计算属性的名称与vuex不一致的时候 用对象形式
...mapState({myname:"name",mymajor:"major"}),
}
Action 提交的是 mutation,而不是直接变更状态。Action 可以包含任意异步操作。
// actions响应组件中的动作
//context 上下文,value组件传递过来的值
//可以包含定时器,ajax代码,有业务逻辑使用action,无业务逻辑直接使用mutations
//index.js中
const actions = {
editwait(context,value){
setTimeout(()=>{
context.commit('editmajor',value);
},3000)
}
}
在组件中使用: $store.dispatch('对应的 action 回调名') 触发
methods:{
editwait(str){
this.$store.dispatch('editwait',str);
}
}
用数据映射触发
import {mapActions } from 'vuex'
methods:{
...mapActions(['editwait']),
}
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。
index.js:
// mutations操作数据state
const mutations = {
editname(state,value){
state.name=value;
},
editmajor(state,value){
state.major=value;
},
}
组件中触发:
methods:{
editname(){
this.$store.commit('editname','2209班')
},
editmajor(){
this.$store.commit('editmajor','vue')
},
}
此时的mutations 无业务逻辑,就是更改状态。
数据映射方法:
import {mapActions } from 'vuex'
methods:{
...mapActions(['editwait']),
}
有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数,也就是对状态在加工:
index.js:
//getter 从 store 中的 state 中派生出一些状态
const getters={
randmajor(state){
return state.major+Math.ceil(Math.random()*9) + Math.ceil(Math.random()*9) + Math.ceil(Math.random()*9);
}
}
组件中调用数据:
专业+随机数:{{randmajor}}
computed:{
randmajor(){
return this.$store.getters.randmajor;
}
},
数据映射方法:
专业+随机数:{{randmajor}}
import {mapGetters } from 'vuex'
computed:{
...mapGetters(['randmajor']),
},
三点运算符的形式书写
mapMutations和mapActions:
借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
mapState和mapGetters:
mapState(mapGetters)生成计算属性,从state中读取状态(对象形式)
index.js部分
- //需包含actions,mutations,state
- // 引入vue
- import Vue from 'vue'
-
- // 引入vuex
- import Vuex from 'vuex'
-
- // 应用vue插件
- Vue.use(Vuex)
-
- //1
- // 准备state存储数据
- const state = {
- //状态对象
- name:'2209',
- major:'web前端',
- }
-
- // actions响应组件中的动作 可以包含任意异步操作
- const actions = {
- editwait(context,value){
- setTimeout(()=>{
- context.commit('editmajor',value);
- },3000)
- }
- }
-
- // mutations操作数据state
- const mutations = {
- editname(state,value){
- state.name=value;
- },
- editmajor(state,value){
- state.major=value;
- },
- }
-
- //getter 从 store 中的 state 中派生出一些状态
- const getters={
- randmajor(state){
- return state.major+Math.ceil(Math.random()*9) + Math.ceil(Math.random()*9) + Math.ceil(Math.random()*9);
- }
- }
-
-
-
- //创建store并导出
- const store = new Vuex.Store({
- actions,
- mutations,
- state,
- getters
- })
- //默认导出store
- export default store
组件1
- <div>
-
-
- <h2>班级:{{myname}},专业:{{mymajor}}h2>
- <h3>专业+随机数:{{randmajor}}h3>
- <p>姓名:张三,年龄:18p>
- <button @click="editname('2209班')">修改班级button>
- <button @click="editmajor('vue')">修改专业button>
- <button @click="editwait('java')">等3s更改专业button>
- div>
- <script>
- import {mapActions, mapGetters, mapMutations, mapState, } from 'vuex'
- export default {
- name:'ZhangSan',
- computed:{
- // name(){
- // return this.$store.state.name;
- // },
- // major(){
- // return this.$store.state.major;
- // }
-
- // 当计算属性的名称与vuex一致的时候 用数组形式
- // ...mapState(["name","major"]),
- // 当计算属性的名称与vuex不一致的时候 用对象形式
- ...mapState({myname:"name",mymajor:"major"}),
-
- // randmajor(){
- // return this.$store.getters.randmajor;
- // }
- ...mapGetters(['randmajor']),
- },
- methods:{
- editname(){
- this.$store.commit('editname','2209班')
- },
- editmajor(){
- this.$store.commit('editmajor','vue')
- },
- ...mapMutations(['editname','editmajor']),
-
- // editwait(str){
- // this.$store.dispatch('editwait',str);
- // }
- ...mapActions(['editwait']),
-
- }
- }
- script>
- <style scoped>
-
- style>
组件2
- <div>
-
-
- <h2>班级:{{myname}},专业:{{mymajor}}h2>
- <h3>专业+随机数:{{randmajor}}h3>
- <p>姓名:李四,年龄:20p>
- div>
- <script>
- import {mapState,} from 'vuex'
- export default {
- name:'LiSi',
- computed:{
- // name(){
- // return this.$store.state.name;
- // },
- // major(){
- // return this.$store.state.major;
- // }
-
- // 当计算属性的名称与vuex一致的时候 用数组形式
- // ...mapState(["name","major"]),
- // 当计算属性的名称与vuex不一致的时候 用对象形式
- ...mapState({myname:"name",mymajor:"major"}),
- randmajor(){
- return this.$store.getters.randmajor;
- }
-
- }
- }
- script>
- <style scoped>
-
- style>
整体效果:

共享状态,通过store把数据共享给两个组件,所以组件里的数据状态会随store里的数据变化而变化
Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割在模块中使用:namespaced: true, 命名空间,添加之后,当前模块下的标识符可以和其它模块相同,用于解决不同模块的命名冲突问题
就上面一个示例来进行模块化编码:
index,js部分
- //需包含actions,mutations,state
- // 引入vue
- import Vue from 'vue'
-
- // 引入vuex
- import Vuex from 'vuex'
-
- // 应用vue插件
- Vue.use(Vuex)
-
-
- const Persons={
- namespaced:true,
- state:{
- //状态对象
- name:'2209',
- major:'web前端',
- },
- actions:{
- editwait(context,value){
- setTimeout(()=>{
- context.commit('editmajor',value);
- },3000);
- }
- },
- mutations:{
- editname(state,value){
- state.name=value;
- },
- editmajor(state,value){
- state.major=value;
- },
- },
- getters:{
- randmajor(state){
- return state.major+Math.ceil(Math.random()*9) + Math.ceil(Math.random()*9) + Math.ceil(Math.random()*9);
- }
- }
- }
-
-
- //创建store并导出
- const store = new Vuex.Store({
- modules:{
- Persons
- }
- })
- //默认导出store
- export default store
组件1
- <div>
-
-
- <h2>班级:{{myname}},专业:{{mymajor}}h2>
- <h3>专业+随机数:{{randmajor}}h3>
- <p>姓名:张三,年龄:18p>
- <button @click="editname('2209班')">修改班级button>
- <button @click="editmajor('vue')">修改专业button>
- <button @click="editwait('java')">等3s更改专业button>
- div>
- <script>
- import {mapActions, mapGetters, mapMutations, mapState, } from 'vuex'
- export default {
- name:'ZhangSan',
- computed:{
- ...mapState('Persons',{myname:"name",mymajor:"major"}),
- ...mapGetters('Persons',['randmajor']),
- },
- methods:{
- ...mapMutations('Persons',['editname','editmajor']),
- ...mapActions('Persons',['editwait']),
- }
- }
- script>
- <style scoped>
-
- style>
组件2
- <div>
-
-
- <h2>班级:{{myname}},专业:{{mymajor}}h2>
- <h3>专业+随机数:{{randmajor}}h3>
- <p>姓名:李四,年龄:20p>
- div>
- <script>
- import {mapState,mapGetters} from 'vuex'
- export default {
- name:'LiSi',
- computed:{
- ...mapState('Persons',{myname:"name",mymajor:"major"}),
- ...mapGetters('Persons',['randmajor']),
- }
- }
- script>
- <style scoped>
-
- style>
代码运行效果和上例一样