Vuex 简介

Vuex 是一个 Vue 的状态管理工具,状态就是数据。

大白话:Vuex 是一个插件,可以帮我们管理 Vue 通用的数据 (多组件共享的数据)。例如:购物车数据 个人信息数

使用场景

  • 某个状态 在 很多个组件 来使用 (个人信息)
  • 多个组件 共同维护 一份数据 (购物车)

优势

  1. 共同维护一份数据,数据集中化管理
  2. 响应式变化
  3. 操作简洁( Vuex 提供了一些辅助函数)

1683178293366.png

创建 Vuex 空仓库

  1. 在终端使用指令 yarn add vuex@3或者npm i vuex@3
1
2
yarn add vuex@3
npm i vuex@3
  1. 新建 store/index.js 文件放置 vuex

image.png

  1. 创建仓库 store/index.js
1
2
3
4
5
6
7
8
9
10
11
12
// 导入 vue
import Vue from 'vue'
// 导入 vuex
import Vuex from 'vuex'
// vuex也是vue的插件, 需要use一下, 进行插件的安装初始化
Vue.use(Vuex)

// 创建仓库 store
const store = new Vuex.Store()

// 导出仓库
export default store
  1. 在 main.js 中导入挂载到Vue实例上
1
2
3
4
5
6
7
8
9
10
11
12
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App),
  store
}).$mount('#app')
  1. 测试打印 store
1
2
3
4
5
6
7
<script>
export default {
  created () {
    console.log(this.$store)
  }
}
</script>

image.png

State 状态

  1. 提供数据:
  • State提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储。
  • 打开项目中的store.js文件,在state对象中可以添加我们要共享的数据。
1
2
3
4
5
6
const store = new Vuex.Store({
  state: {
    title: '我是标题',
    count: 100
  }
})
  1. 使用数据
  • 使用 store 访问数据
1
2
3
4
5
6
7
8
获取 store:
1.Vue模板中获取 this.$store
2.js文件中获取 import 导入 store


模板中: {{ $store.state.xxx }}
组件逻辑中: this.$store.state.xxx
JS模块中: store.state.xxx

辅助函数 mapState

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
    <div>
        <h2>第一小组件</h2>
        <!-- 直接使用仓库里的变量,相当于this.$store.state.count -->
        从Vuex中获取的值:<label for="">{{ count }}</label>
        <br>
        <button>+1</button>
    </div>
</template>

<script>
import { mapState } from 'vuex' // 导入mapState辅助函数

export default {
  name: 'Son1Com',
  computed: {
    ...mapState(['count']) // 展开运算符映射
  }
}
</script>

Vuex 的单向数据流

Vuex 同样遵循单向数据流,组件中不能直接修改仓库的数据

1
2
3
4
5
6
methods:{
handleAdd (n) {
// 错误代码(vue默认不会监测,监测需要成本)
this.$store.state.count++
},
}

因为浏览器默认不会检测到这个错误,所以很难察觉到错误

开启严格模式,strick: true可以将此类错误报告出来

1
2
3
4
5
6
7
8
const store = new Vuex.Store({
  // 开启严格模式
  strict: true,
  state: {
    title: '我是标题',
    count: 100
  }
})

mutations 对象

mutations 是 vuex 的一个对象,用来修改 state 数据的,必须时同步操作

传递参数:this.$store.commit('xxx', 参数)

  1. 定义 mutations 对象,对象中存放修改 state 的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const store = new Vuex.Store({
  // 开启严格模式
  strict: true,
  // state数据,存放共享的数据
  state: {
    title: '我是标题',
    count: 100
  },
  // mutations对象,存放操作state的方法
  mutations: {
    addCount (state, n) {
      state.count += n
    }
  }
})
  1. 组件中调用 mutations
1
2
3
4
5
methods: {
handleAdd (a) {
this.$store.commit('addCount', a)
}
}
  • 当有多个参数传递时
1
2
3
4
this.$store.commit('addCount', {
count: 10,
xxx:
})

用 Vuex 实现 input 双向绑定

  1. 输入框渲染内容 :value=""
  2. 监听输入的数值 @input="handleInput"
  3. 编写函数调用 mutations
1
2
3
4
5
6
7
8
9
10
11
12
13
<input :value="count" @input="handleInput" type="number">

<script>
export default {
  ...
  methods: {
    handleInput (e) {
      const num = e.target.value
      this.$store.commit('changeCount', num)
    }
  },
  ...
</script>
  1. 封装 mutations 处理函数
1
2
3
changeCount (state, newCount) {
state.count = newCount
}

辅助函数 mapMutations

用法和 mapState 很像

1
2
3
4
5
6
7
8
import { mapState, mapMutations, mapActions } from 'vuex'
export default {
  ...
  methods: {
    ...mapMutations(['changeCount'])
  },
  ...
}

调用方法

1
2
3
4
5
6
7
this.changeCount(n)
// 等价于下面的写法
methods: {
changeCount (n) {
this.$store.commit('changeCount', n)
}
}

actions 对象

mutations 只能处理同步操作

actions 用于处理异步操作

  1. 提供actions 方法
1
2
3
4
5
6
7
actions: {
setAsyncCount (context, num) {
setTimeout(() => {
context.commit('changeCount', num)
}, 1000)
}
}
  1. 在组件中调用
1
2
3
setAsyncCount () {
this.$store.dispatch('setAsyncCount', 666)
}

辅助函数 mapActions

mapActions 是位于 actions中的方法提取出来,映射到组件methods中

1
2
3
4
5
6
7
8
import { mapState, mapMutations, mapActions } from 'vuex'
export default {
  ...
  methods: {
    ...mapActions(['setAsyncCount'])
  },
  ...
}

getters

除了state之外,有时我们还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到getters

例如,state中定义了list,为1-10的数组,显示出大于5的数据

1
2
3
state: {
list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}
  1. 定义getters
1
2
3
4
5
getters: {
// getters函数的第一个参数是 state
// 必须要有返回值
filterList: state => state.list.filter(item => item > 5)
}
  1. 使用getters
1
<div>{{ $store.getters.filterList }}</div>

辅助函数 mapGetters

mapGetters 是位于getters中的方法提取出来,映射到组件computed中

1
2
3
computed: {
...mapGetters(['filterList'])
}

调用:

1
<div>{{ filterList }}</div>

modules 模块

  1. 模块定义,在 store/modules/ 文件夹下,创建模块文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const state = {
userInfo: {
name: 'zs',
age: 18
}
}
const mutations = {}
const actions = {}
const getters = {}

export default {
state,
mutations,
actions,
getters
}
  1. 注册模块,在 store/index.js 文件内导入注册这个模块
1
2
3
4
5
6
7
8
9
import user from './modules/user'
import setting from './modules/setting'

const store = new Vuex.Store({
modules:{
user,
setting
}
})

获取数据

获取 state 数据

可以直接使用模块名访问:$store.state.模块名.xxx

使用默认根级别的映射:mapState(['xxx'])

也可以使用子模块映射: mapState('模块名', ['xxx']) - 需要开启命名空间 namespaced:true

获取 getters 数据

可以直接使用模块名访问:$store.getters['模块名/xxx']

使用默认根级别的映射:mapGetters(['xxx'])

也可以使用子模块映射: mapGetters('模块名', ['xxx']) - 需要开启命名空间 namespaced:true

获取 mutations 数据

注意:默认模块中的 mutation 和 actions 会被挂载到全局,需要开启命名空间,才会挂载到子模块。

可以直接使用模块名访问:$store.commit('模块名/xxx', 额外参数)

使用默认根级别的映射:mapMutations(['xxx'])

也可以使用子模块映射: mapMutations('模块名', ['xxx']) - 需要开启命名空间 namespaced:true

获取 actions 数据

注意:默认模块中的 mutation 和 actions 会被挂载到全局,需要开启命名空间,才会挂载到子模块。

可以直接使用模块名访问:$store.dispatch('模块名/xxx', 额外参数)

使用默认根级别的映射:mapActions(['xxx'])

也可以使用子模块映射: mapActions('模块名', ['xxx']) - 需要开启命名空间 namespaced:true

1
2
3
4
5
6
7
export default {
namespaced: true,
state,
mutations,
actions,
getters
}