0

0

通俗易懂!详解VUEX状态仓库管理

藏色散人

藏色散人

发布时间:2022-08-10 14:25:31

|

1969人浏览过

|

来源于jianshu

转载

vuex 是一个专为 vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。简单来说就是:应用遇到多个组件共享状态时,使用vuex。

VueX 是一个专门为 Vue.js 应用设计的状态管理构架,统一管理和维护各个vue组件的可变化状态

场景:多个组件共享数据或者是跨组件传递数据时

vuex的五个核心概念:

  • State:共享状态,vuex的基本数据,用来存储变量,相当于组件data里的数据,只不过此时变成了全局变量。
  • Getter:基于state的派生状态,相当于组件中的computed中的属性。
  • Mutation:更改vuex中store共享状态的方法,通过提交mutation来去修改状态,进行同步操作数据,通常用于action获取异步数据,获取通过commit提交数据给mutation,在mutation同步操作state中的数据。
  • action:支持异步操作,可用于异步获取请求中的数据,并将获取的数据同步commit提交给mutation,实现ajax异步请求数据,mutation将其数据同步到state中。
  • modules:模块化vuex,为了方便后期对于项目的管理,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。

优势和劣势有哪些?
优势主要就是可以全局共享数据,方法。方便统一管理
劣势的话,页面刷新后state的变量都会还原清空,不会像cookies一样持久性存储

页面刷新后vuex的state数据丢失怎么解决?
先说一下为什么会丢失呢?
因为store里的数据是保存在运行内存中的,当页面刷新时页面会重新加载vue实例,store里面的数据就会被重新赋值

如何避免?
其实主要还是看使用的场景是怎样的,如果想某些数据持久性保留也可以搭配使用cookies或者localStorage。比如一些登录的信息等。
比如请求拿到了登录信息后可以先存在localStorage,将state里的变量值和sessionStorage里面的绑定,mutations中修改的时候同时修改state和localStorage。最后页面直接使用vuex中的变量。【相关推荐:vue.js视频教程

立即学习前端免费学习笔记(深入)”;


正式进入使用

vuex的安装
打开终端,输入命令行npm install vuex --save进行下载vuex

vuex应用核心管理仓库 构建store

这里新建store文件夹,创建一个js取名为index.js,
在index里 ,通过将state,mutations,actions,getters引入到store中,并暴露出store对象。

下面为index.js的代码

/*
  vuex最核心的管理对象 store
*/import Vue from 'vue';import Vuex from 'vuex';
 // 分别引入这四个文件  这四个文件的内容和用法在下面分别讲到import state from './state';import mutations from './mutations';import actions from './actions';import getters from './getters';
 //声明使用插件Vue.use(Vuex)//new 一个Vuex的对象,将state,mutation,action,getters配置到vuex的store中,方便管理数据export default new Vuex.Store({  
  state,
  mutations,
  actions,
  getters,})

挂载store到vue实例上
main.js中

import store from './store'// ..........new Vue({
  el: '#app',
  router,
  store,   // ***
  render: h => h(App)})

state状态管理数据

我们通常将需要进行管理的共享数据,放入state中,使其形似为全局变量,对于需要的组件进行引入该state状态数据。

const state = {
  userId: '',
  token: '',
  name: '',
  avatar: '',
  introduction: '',
  roles: [],
  tenantId: 1,
  userInfo: null};

mutations 同步提交数据

mutations用于更改state中的状态逻辑的,且为同步更改state中的状态数据。
需要知道的是在vuex中只能通过mutation来去修改state对象,
可以通过获取actions获取到的数据去修改state,也可以在mutations模块中直接定义方法来去更改状态数据。

const mutations = {
  SET_TOKEN: (state, token) => {
    state.token = token;
  },
  SET_USERID: (state, userId) => {
    state.userId = userId;
  },
  SET_NAME: (state, name) => {
    state.name = name;
  },
  SET_ROLES: (state, roles) => {
    state.roles = roles;
  },
  SET_TENANTID: (state, roles) => {
    state.tenantId = roles;
  },
  SET_USER_INFO: (state, userInfo) => {
    state.userInfo = userInfo;
  }};

通过mutations和下面的actions模块,大家也可以看出commit是用于调用mutation模块中的。
在组件中调用其mutation模块的代码为:

this.$store.commit('SET_TOKEN', token_data)

actions 的异步操作

actions与其mutations类似,但其可以进行异步操作,
且将异步操作获取的数据提交给mutations,使得mutations更改state中的状态数据, 这里常常用于获取ajax请求中的数据(因为是异步),并将其获取的数据commit提交给mutations 使得 state数据状态的更新。

和mutations 的不同之处在于:Action 提交的是 mutation,而不是直接变更状态。Action 可以包含任意异步操作。

举例

/* 下面就是通过actions执行异步Ajax请求,
得到数据后,
通过commit的方法调用mutations 从而更新数据
例如:  commit('SET_TOKEN', data.uuid);
*/const actions = {
  login({ commit }, userInfo) {  // 用户登录
    const params = userInfo;
    params.userName = userInfo.userName.trim()
    return new Promise((resolve, reject) => {
      getLogin(params)
        .then((response) => {
          const { status, message, data } = response || {};
          if (status === 200) {
            // 存入 参数: 1.调用的值 2.所要存入的数据
            commit('SET_USER_INFO', data);
            commit('SET_TOKEN', data.uuid);
            commit('SET_USERID', data.id);
            commit('SET_ROLES', data.roles);
            commit('SET_NAME', data.realName);
            commit('SET_TENANTID', data.tenantId || 1);
            setToken(data.uuid);
            db.save('userInfo', data);
            db.save('tenantId', data.tenantId || 1);
            localStorage.setItem('loginToken', data.uuid);
            resolve(data);
          } else {
            // ElementUI.Message.error(message);  // axios拦截统一提示了
          }
        })
        .catch((error) => {
          // ElementUI.Message.error(error.message); // axios拦截统一提示了
          reject(error);
        });
    });
  },}

这个actions在组件中的调用方法就是:

豆包手机助手
豆包手机助手

豆包推出的手机系统服务级AI助手

下载
 this.$store.dispatch('user/login', postUser)
            .then(res => {
               // .............
              })// 我这里的login方法写在了user.js这个module里 所以这里调用是 user/login// 下面会讲到module

Getters 对state进行加工

Getters相当于computed计算属性,用于加工处理state状态数据,有其两个默认参数,第一个默认参数为state,第二个默认参数为getters。

const getters={
  plusCount(state){
    return state.count + 1
  },
 //获取state中状态数据对象,和获取getters模块中plusCount数据
  totalCount(state,getters){
    return getters.plusCount + state.count  }}

在组件中调用该方法的代码片段为:

this.$store.getters.totalCount()

在Vue组件中获得Vuex状态

store实例中读取状态最简单的方法就是在计算属性中返回某个状态,由于Vuex的状态存储是响应式的,所以在这里每当store.state.count变化的时候,都会重新求取计算属性,进行响应式更新。

 computed: {
        count: function(){
            return this.$store.state.count        }
    },

那么对于以上的store我们就简单介绍完了,相信大家看完后对于vuex会有一定的理解。那么这个时候我们要想,是不是使用this.$store.statethis.$store.getters.xxx感到麻烦呢?下面我们介绍另一种引入state和getters的方式

辅助函数 mapState 和 mapGetters

对于上述的在组件中引用state和getters的方法是不是感到麻烦呢?使用mapState你将会感受到便利。
组件中这样使用

//首先我们需要先将辅助函数引入import { mapGetters,mapState } from 'vuex'
 export default {
 computed: {

  // 使用对象展开运算符将 getter 混入 computed 对象中
  ...mapGetters( ['plusCount','totalCount'] )

 // 使用对象展开运算符将 state 混入 computed 对象中
    ...mapState( ['userInfo','count'] )

 },methods:{
    getData(){
        // 这里就能直接使用了  直接使用state 和getters里的数据
        //  this.userInfo 
        // this.plusCount
        
    }}}

Module子模块化管理

store文件夹下的index.js代码如下

import Vue from 'vue'import Vuex from 'vuex'import getters from './getters'Vue.use(Vuex)const modulesFiles = require.context('./modules', true, /\.js$/)const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
  const value = modulesFiles(modulePath)
  modules[moduleName] = value.default
  return modules}, {})const store = new Vuex.Store({
  modules,
  getters})export default store

文件目录如图

0c6dfca7c3329646836381c630d4f6b.jpg

举例 api.js

import { getKey, getLogin, logout, getInfo } from '@/api/user';import { setToken, removeToken } from '@/utils/auth';import db from '@/utils/localstorage';import router, { resetRouter } from '@/router';import ElementUI from 'element-ui';const state = {
  userId: '',
  token: '',
  name: '',
  avatar: '',
  introduction: '',
  roles: [],
  tenantId: 1,
  userInfo: null
  // roles: ['9999']};const mutations = {
  SET_TOKEN: (state, token) => {
    state.token = token;
  },
  SET_USERID: (state, userId) => {
    state.userId = userId;
  },
  SET_NAME: (state, name) => {
    state.name = name;
  },
  SET_ROLES: (state, roles) => {
    state.roles = roles;
  },
  SET_TENANTID: (state, roles) => {
    state.tenantId = roles;
  },
  SET_USER_INFO: (state, userInfo) => {
    state.userInfo = userInfo;
  }};const actions = {
  // 获取密钥
  getKey({ commit }) {
    return new Promise((resolve, reject) => {
      getKey()
        .then((response) => {
          resolve(response);
        })
        .catch((error) => {
          reject(error);
        });
    });
  },

  // 用户登录
  login({ commit }, userInfo) {
    // const { username, password } = userInfo;
    const params = userInfo;
    params.userName = userInfo.userName.trim()
    return new Promise((resolve, reject) => {
      // console.log(username, password);
      // setToken(state.token)
      // localStorage.setItem('loginToken', state.token)
      getLogin(params)
      // getLogin({ userName: username.trim(), password: password })
        .then((response) => {
          const { status, message, data } = response || {};
          if (status === 200) {
            // 存入 参数: 1.调用的值 2.所要存入的数据
            commit('SET_USER_INFO', data);
            commit('SET_TOKEN', data.uuid);
            commit('SET_USERID', data.id);
            commit('SET_ROLES', data.roles);
            commit('SET_NAME', data.realName);
            commit('SET_TENANTID', data.tenantId || 1);
            setToken(data.uuid);
            db.save('userInfo', data);
            db.save('tenantId', data.tenantId || 1);
            localStorage.setItem('loginToken', data.uuid);
            resolve(data);
          } else {
            // ElementUI.Message.error(message);  // axios拦截统一提示了
          }
        })
        .catch((error) => {
          // ElementUI.Message.error(error.message); // axios拦截统一提示了
          reject(error);
        });
    });
  },

  // 获取用户信息
  getInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      getInfo(state.token)
        .then((response) => {
          const { data } = response;
          data.roles = response.data.rights.map(String);
          if (!data) {
            reject('验证失败,请重新登录。');
          }
          const loginMessage = {
            memberId: data.id,
            userName: data.name,
            userTel: data.mobile,
            realName: data.realName,
            incorCom: data.incorCom,
            virtualCor: data.virtualCor,
            deptId: data.deptId,
            deptpath: data.deptpath,
            deptName: data.deptName          };
          localStorage.setItem('loginMessage', JSON.stringify(loginMessage));
          const { id, roles, realName } = data;
          // 角色必须是非空数组!
          if (!roles || roles.length <= 0) {
            reject('getInfo: 角色必须是非空数组!');
          }
          commit('SET_USERID', id);
          commit('SET_ROLES', roles);
          commit('SET_NAME', realName);
          localStorage.setItem('userRights', roles);
          // commit('SET_AVATAR', avatar)
          // commit('SET_INTRODUCTION', introduction)
          resolve(data);
        })
        .catch((error) => {
          reject(error);
        });
    });
  },

  // 用户登出
  logout({ commit, state }) {
    return new Promise((resolve, reject) => {
      logout(state.token)
        .then(() => {
          commit('SET_TOKEN', '');
          commit('SET_ROLES', []);
          db.remove('router');
          removeToken();
          resetRouter();
          resolve();
        })
        .catch((error) => {
          reject(error);
        });
    });
  },

  // 删除token
  resetToken({ commit }) {
    return new Promise((resolve) => {
      commit('SET_TOKEN', '');
      commit('SET_ROLES', []);
      removeToken();
      resolve();
    });
  },

  // 动态修改权限
  changeRoles({ commit, dispatch }, role) {
    return new Promise(async(resolve) => {
      const token = role + '-token';

      commit('SET_TOKEN', token);
      setToken(token);

      const { roles } = await dispatch('getInfo');
      console.log(roles, 'rolesrolesroles');
      resetRouter();

      // 根据角色生成可访问路由映射
      const accessRoutes = await dispatch('permission/generateRoutes', roles, {
        root: true
      });

      // 动态添加可访问路由
      router.addRoutes(accessRoutes);

      // 重置已访问视图和缓存视图
      dispatch('tagsView/delAllViews', null, { root: true });

      resolve();
    });
  }};export default {
  namespaced: true,
  state,
  mutations,
  actions};

这样后可以按功能分module使用

页面中调用就是

// 使用mutationsthis.$store.commit('api/SET_T', keys);// 使用actionsthis.$store.dispatch('user/login', postUser).then(res => {})// 如果没有分module // 那就是 this.$store.commit('SET_T', keys);// 直接调用方法

写完自己也感觉好简单噢(⊙-⊙)

不明白的童鞋在评论区留言咯 ヾ(•ω•`)o

相关专题

更多
Golang gRPC 服务开发与Protobuf实战
Golang gRPC 服务开发与Protobuf实战

本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

8

2026.01.15

公务员递补名单公布时间 公务员递补要求
公务员递补名单公布时间 公务员递补要求

公务员递补名单公布时间不固定,通常在面试前,由招录单位(如国家知识产权局、海关等)发布,依据是原入围考生放弃资格,会按笔试成绩从高到低递补,递补考生需按公告要求限时确认并提交材料,及时参加面试/体检等后续环节。要求核心是按招录单位公告及时响应、提交材料(确认书、资格复审材料)并准时参加面试。

44

2026.01.15

公务员调剂条件 2026调剂公告时间
公务员调剂条件 2026调剂公告时间

(一)符合拟调剂职位所要求的资格条件。 (二)公共科目笔试成绩同时达到拟调剂职位和原报考职位的合格分数线,且考试类别相同。 拟调剂职位设置了专业科目笔试条件的,专业科目笔试成绩还须同时达到合格分数线,且考试类别相同。 (三)未进入原报考职位面试人员名单。

58

2026.01.15

国考成绩查询入口 国考分数公布时间2026
国考成绩查询入口 国考分数公布时间2026

笔试成绩查询入口已开通,考生可登录国家公务员局中央机关及其直属机构2026年度考试录用公务员专题网站http://bm.scs.gov.cn/pp/gkweb/core/web/ui/business/examResult/written_result.html,查询笔试成绩和合格分数线,点击“笔试成绩查询”按钮,凭借身份证及准考证进行查询。

11

2026.01.15

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

65

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

36

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

75

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

21

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

35

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
uni-app电商系统实战精讲课程
uni-app电商系统实战精讲课程

共66课时 | 15.4万人学习

Vuex参考手册
Vuex参考手册

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号