vuex
前置
注意:vue2 安装 vuex 需下载指定版本,否则会报vuex版本过高的错误
npm install vuex@3.4.0 --save
核心概念
创建 store 并挂载
-
创建 src/store.js
// 导入 Vue Vuex import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); // 创建并暴露 store 实例 export default new Vuex.Store({ state: {}, mutations: {}, actions: {}, }); -
main.js
import Vue from 'vue'; import App from './App.vue'; // 引入 store import store from './store'; Vue.config.productionTip = false; // 挂载 store new Vue({ store, render: h => h(App) }).$mount('#app');
state
定义共享状态变量的地方
-
定义 - src/store.js
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); export default new Vuex.Store({ // 定义数据 state: { count: 0, }, mutations: {}, actions: {}, }); -
使用 - a.vue
推荐使用 mapState
<template> <!-- 使用 store 中 state 内定义的共享状态 方法一:$store.state.状态名 方法二: 1. 引入 vuex 中 mapState 方法 2. 在 computed 中 映射状态 3. template 中 直接使用 --> <div> <h1>a 页面当前最新的 count 值为:{{ $store.state.count }}</h1> <h2>{{ count }}</h2> </div> </template> <script> import { mapState } from 'vuex'; export default { computed: { ...mapState(['count']), }, }; </script>
mutations
集中修改 state 的状态的地方
-
定义 - src/store.js
mutations: { // 不传参写法 add(state) { state.count++; }, // 传参写法 addN(state, step) { state.count += step; }, }, -
使用 - a.vue
推荐使用 mapMutations
<template> <div> <h2>{{ count }}</h2> <button @click="handleAdd">+1</button> <button @click="handleAddN">+N</button> </div> </template> <script> import { mapState, mapMutations } from 'vuex'; export default { computed: { ...mapState(['count']), }, methods: { /** 调用 mutations 中的方法 * 方法一: * 没有参数:this.$store.commit('函数名') * 带参数 :this.$store.commit('函数名',参数) * 方法二: * 1. 引入 mapMutations * 2. 使用 ...mapMutations(['add'...]) 将 mutation 函数映射为 methods 方法 * 3. this.方法名 调用 * commit 的作用就是调用某个 mutation 函数 * */ ...mapMutations(['add', 'addN']), handleAdd() { // 修改 state 值,必须通过 mutations 方法修改,以下方法是错误示例 // this.$store.state.count++; // this.$store.commit('add'); this.add(); }, handleAddN() { // this.$store.commit('addN', 10); this.addN(20); }, }, }; </script>
actions
异步函数 必须放在 actions 中,然后调用 mutation 中的修改函数。直接在 mutations 中修改状态无效
常见有 actions 函数中 发起异步请求
-
定义 - src/store.js
actions: { // 在 actions 中不能直接修改 state 中的数据,必须通过 context.commit() 来触发某个 mutation 函数 才行 // 无参 asyncAdd(context) { setTimeout(() => { context.commit('add'); }, 2000); }, // 带参 asyncAddN(context, step) { setTimeout(() => { context.commit('addN', step); }, 2000); }, }, -
使用 - a.vue
<template> <div> <h2>{{ count }}</h2> <button @click="handleAsyncAdd">async +1</button> <button @click="handleAsyncAddN">async +N</button> <!-- 使用 mapActions 简写 --> <!-- <button @click="asyncAdd()">async +1</button> --> <!-- <button @click="asyncAddN(6)">async +N</button> --> </div> </template> <script> import { mapState, mapMutations, mapActions } from 'vuex'; export default { computed: { ...mapState(['count']), }, methods: { /** 触发 actions 函数 * 方法一:this.$store.dispatch('actions 函数名') * 方法二: * dispatch:专门来触发 actions 函数 */ ...mapActions(['asyncAdd', 'asyncAddN']), handleAsyncAdd() { // 无参 // this.$store.dispatch('asyncAdd'); this.asyncAdd(); }, handleAsyncAddN() { // 带参 // this.$store.dispatch('asyncAddN', 30); this.asyncAddN(5); }, }, }; </script>
getter
不会修改 store 中的原数据,只是对 store 中已有的数据进行加工形成新的数据,起到包装数据的作用,类似 vue 中 计算属性的作用
-
定义 - src/store.js
getters: { showCount: state => { return `当前最新的数据是【${state.count}】 `; }, }, -
使用 - a.vue
<template> <!-- 调用 getters 方法一:$store.getters.函数名 方法二: 1. 引入 mapGetters 2. 在 computed 中 使用 ...mapGetters(['函数名']), 3. template 中 直接使用 --> <div> <h2>{{ count }}</h2> <!-- <h2>{{ $store.getters.showCount }}</h2> --> <h2>{{ showCount }}</h2> </div> </template> <script> import { mapState, mapGetters } from 'vuex'; export default { computed: { ...mapState(['count']), ...mapGetters(['showCount']), }, </script>
module
-
store/index.js
// 导入 Vue Vuex import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); // 创建并暴露 store 实例 export default new Vuex.Store({ modules: { // 模块对象中每个属性都是一个独立模块, 可以拥有自己的 state / mutations / actions user: { state: { count: 0, }, mutations: {}, actions: {}, }, }, });
模块状态下 state 的使用
-
test.vue
<template> <div> <h1>{{ $store.state.user.count }}</h1> </div> </template>
模块状态下 mutations 的使用
-
store/index.js
modules: { // 模块对象中每个属性都是一个独立模块, 可以拥有自己的 state / mutations / actions user: { state: { count: 0, }, mutations: { add(state, step) { if ((step ?? '') === '') { state.count++; return; } state.count += step; }, }, actions: {}, }, }, -
test.vue
<template> <div> <h1>{{ $store.state.user.count }}</h1> <button @click="handleAdd"> 点击++ </button> <button @click="$store.commit('add')"> 2222点击++ </button> <button @click="add()"> 辅助函数点击++ </button> </div> </template> <script> import { mapMutations } from 'vuex'; export default { /** * 方法一:this.$store.commit('函数名') * 方法二:mapMutations 辅助函数 * */ methods: { ...mapMutations(['add']), handleAdd() { this.$store.commit('add'); }, }, }; </script>
命名空间锁🎈
-
store/index.js
modules: { // 模块对象中每个属性都是一个独立模块, 可以拥有自己的 state / mutations / actions user: { // 命名空间锁 namespaced: true, state: { count: 0, }, mutations: { add(state, step) { if ((step ?? '') === '') { state.count++; return; } state.count += step; }, }, actions: {}, }, }, -
命名空间锁下调用 mutations 函数的两种方式 - test.vue
<template> <div> <h1>{{ $store.state.user.count }}</h1> <button @click="handleAdd"> 点击++ </button> <button @click="$store.commit('user/add')"> 2222点击++ </button> <button @click="add()"> 辅助函数点击++ </button> </div> </template> <script> import { mapMutations } from 'vuex'; export default { /** * 方法一:this.$store.commit('模块名/函数名') * 方法二:mapMutations 辅助函数 * */ methods: { ...mapMutations('user', ['add']), handleAdd() { this.$store.commit('user/add'); }, }, }; </script>
创建模块专用辅助函数🎈
-
store/index.js
modules: { // 模块对象中每个属性都是一个独立模块, 可以拥有自己的 state / mutations / actions user: { // 命名空间锁 namespaced: true, //... }, },
-
test.vue
<template> <div> <h1>{{ $store.state.user.count }}</h1> <button @click="add(10)"> 点击++ </button> </div> </template> <script> // 创建模块专用辅助函数 import { createNamespacedHelpers } from 'vuex'; const { mapMutations } = createNamespacedHelpers('user'); export default { methods: { ...mapMutations(['add']), }, }; </script>
getters 的使用
-
store/index.js
// 创建并暴露 store 实例 export default new Vuex.Store({ getters: { count: state => state.user.count, }, modules: { // 模块对象中每个属性都是一个独立模块, 可以拥有自己的 state / mutations / actions user: { // 命名空间锁 namespaced: true, state: { count: 0, }, mutations: { add(state, step) { if ((step ?? '') === '') { state.count++; return; } state.count += step; }, }, actions: {}, }, }, }); -
demo.vue
<template> <div> <h1>{{ $store.getters.count }}</h1> </div> </template>
💥项目中 store 的拆分
-
main.js
import Vue from 'vue'; import App from './App.vue'; // 引入 store import store from './store/index'; Vue.config.productionTip = false; // 挂载 store new Vue({ store, render: h => h(App) }).$mount('#app');
-
store/index.js
// 导入 Vue Vuex import Vue from 'vue'; import Vuex from 'vuex'; import getters from './getters'; import user from './modules/user'; Vue.use(Vuex); // 创建并暴露 store 实例 export default new Vuex.Store({ getters, modules: { user, }, }); -
store/modules/user.js
export default { // 开启 命名空间锁 namespaced: true, state: { count: 0, }, mutations: { add(state, step) { if ((step ?? '') === '') { state.count++; return; } state.count += step; }, }, actions: {}, }; -
store.getters.js
export default { count: state => state.user.count, }; -
App.vue
<template> <div> <h1>{{ $store.getters.count }}</h1> <button @click="add(10)"> 点击++ </button> </div> </template> <script> // 创建模块专用辅助函数 import { createNamespacedHelpers } from 'vuex'; const { mapMutations } = createNamespacedHelpers('user'); export default { methods: { ...mapMutations(['add']), }, }; </script>\