Vue-Element-Admin项目学习笔记(6)Vuex状态管理

news2024/12/4 1:55:23

前情回顾:

vue-element-admin项目学习笔记(1)安装、配置、启动项目
vue-element-admin项目学习笔记(2)main.js
文件分析
vue-element-admin项目学习笔记(3)路由分析一:静态路由
vue-element-admin项目学习笔记(4)路由分析二:动态路由及permission.js
vue-element-admin项目学习笔记(5)路由分析三:动态路由匹配逻辑

关于什么是vuex?和理论部分,本篇不做讨论,假设前提是,你已经学习和掌握了vue基础的小伙伴。

vuex的核心有四个部分:

  • state :状态,也可以理解为变量
  • mutation :操作状态的地方
  • action :操作状态之前需要处理异步或业务逻辑
  • getter :对状态进行包装,理解为计算属性computed

也可以参考我之前发过的一篇:

VueX使用简明笔记

本篇还是围绕Vue-Element-Admin项目,针对Vuex状态管理的角度进行简单分析。

这部分也是非常重要的,关乎项目内部业务逻辑、交互逻辑

1、Vue-Element-Admin项目中vuex仓库概况

Vue-Element-Admin项目的store仓库位置在项目目录/src/store这个路径下。
结构如下:
在这里插入图片描述

  • modules目录内主要存放的一些自定义的子仓库模块,你自己写的,最好也按照规范存到这里

  • ./modules/app.js存储和操作cookie、语言切换、默认尺寸等状态,理解为全局变量也行

  • ./modules/errLog.js定义和操作项目错误日志状态

  • ./modules/permission.js权限状态的定义和操作,这个在动态路由计算那篇中,已经详细聊过了

  • ./modules/settings.js系统设置状态的定义和操作,包括主题等

  • ./modules/tagsView.js小页签状态的定义和操作,下图就是:
    在这里插入图片描述

  • ./modules/user.js重要,用户的状态、状态操作,都在这,比如登录、登出这些逻辑,以及后面会说到的后端校验接口,也是通过它在调用并修改状态

  • ./getters.js对全局需要的一些状态(变量),比如用户信息、动态路由规则、设置等进行集中抽取并暴露。

  • ./index.js是仓库入库,主要完成的工作,是对子仓库模块的引入和注册

2、store入口文件index.js

一步步看注释:

// 引入vue
import Vue from 'vue'
// 引入vuex
import Vuex from 'vuex'
// 引入getters 理解为全局变量
import getters from './getters'
// 使用vuex,因为本质上是插件
Vue.use(Vuex)
// 在modules目录下读取所有模块文件名
const modulesFiles = require.context('./modules', true, /\.js$/)
// 过滤匹配模块名:值 返回modules
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

3、权限状态控制permission.js

一步步看注释:

// 导入动态、静态路由规则
import { asyncRoutes, constantRoutes } from '@/router'

// 具体路由规则与用户roles匹配的工具函数,被filterAsyncRoutes调用
// 返回布尔值
function hasPermission(roles, route) {
  // 规则有元信息 且 元信息 有roles项
  if (route.meta && route.meta.roles) {
    // 开始比对,role在不在route.meta.roles中,返回比对结果
    return roles.some(role => route.meta.roles.includes(role))
  } else {
    //没有元信息,可以返回真,说明没有配置权限,可以访问
    return true
  }
}

// 遍历路由规则与用户roles匹配的工具函数
export function filterAsyncRoutes(routes, roles) {
  const res = []
  // 遍历传过来的所有动态路由规则进行遍历
  routes.forEach(route => {
    // tmp 每一个规则
    const tmp = { ...route }
    // 调用hasPermission方法(布尔值),进行匹配
    if (hasPermission(roles, tmp)) {
      // 子级路由递归计算
      if (tmp.children) {
        tmp.children = filterAsyncRoutes(tmp.children, roles)
      }
      res.push(tmp)
    }
  })

  return res
}

// 两个状态、数组routes、addRoutes
// routes 当前用户所有路由
// addRoutes 当前用户动态路由。权限计算出来的
// 通过浏览器vue插件可以观察看到
const state = {
  routes: [],
  addRoutes: []
}

// mutations操作state
// 给这两个数组赋值
const mutations = {
  SET_ROUTES: (state, routes) => {
    state.addRoutes = routes
    state.routes = constantRoutes.concat(routes)
  }
}
// actions操作异步
// generateRoutes方法,计算生成权限动态路由
const actions = {
  generateRoutes({ commit }, roles) {
    return new Promise(resolve => {
      // 定义一个临时变量
      let accessedRoutes
      // 当前用户的roles中是否包含admin
      if (roles.includes('admin')) {
        // 包含的话,就把所有动态路由规则给它,asyncRoutes是所有动态路由,导入的
        // admin用户不用计算
        accessedRoutes = asyncRoutes || []
      } else {
        //  否则在所有动态路由规则中进行过滤匹配
        accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
      }
      // 提交修改数组
      commit('SET_ROUTES', accessedRoutes)
      resolve(accessedRoutes)
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

4、用户状态控制user.js

// 引入src/api下的user接口,登录login, 退出登录logout, 获取用户信息getInfo
import { login, logout, getInfo } from '@/api/user'
// 引入src/utils/auth下的三个方法:获取getToken, 设置setToken, 删除removeToken
import { getToken, setToken, removeToken } from '@/utils/auth'
// 引入路由以及resetRouter重置路由方法,重置是因为切换用户/切换登录,需要重置
import router, { resetRouter } from '@/router'
// 定义用户信息(数据、状态)
const state = {
  token: getToken(),
  name: '',
  avatar: '',
  introduction: '',
  roles: []
}
// mutations是改变状态的唯一途径
// 改变用户信息的一些操作
const mutations = {
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  SET_INTRODUCTION: (state, introduction) => {
    state.introduction = introduction
  },
  SET_NAME: (state, name) => {
    state.name = name
  },
  SET_AVATAR: (state, avatar) => {
    state.avatar = avatar
  },
  SET_ROLES: (state, roles) => {
    state.roles = roles
  }
}
// 异步操作
const actions = {
  // 用户登录
  login({ commit }, userInfo) {
    const { username, password } = userInfo
    return new Promise((resolve, reject) => {
      login({ username: username.trim(), password: password }).then(response => {
        const { data } = response
        commit('SET_TOKEN', data.token)
        setToken(data.token)
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },

  // get user info
  getInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      getInfo(state.token).then(response => {
        const { data } = response

        if (!data) {
          reject('Verification failed, please Login again.')
        }

        const { roles, name, avatar, introduction } = data

        // roles must be a non-empty array
        if (!roles || roles.length <= 0) {
          reject('getInfo: roles must be a non-null array!')
        }

        commit('SET_ROLES', roles)
        commit('SET_NAME', name)
        commit('SET_AVATAR', avatar)
        commit('SET_INTRODUCTION', introduction)
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  },

  // user logout
  logout({ commit, state, dispatch }) {
    return new Promise((resolve, reject) => {
      // 先调了退出登录的接口logout,传入token,后端作废处理后返回
      logout(state.token).then(() => {
        commit('SET_TOKEN', '')//清理仓库中的token
        commit('SET_ROLES', [])//清理仓库中的权限
        removeToken()//移除cookie中的token
        resetRouter()//重置路由,清理为当前用户计算的动态路由规则
        //  清空tagsView(就是打开页面的小标签)
        dispatch('tagsView/delAllViews', null, { root: true })

        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },

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

  // dynamically modify permissions
  async changeRoles({ commit, dispatch }, role) {
    const token = role + '-token'

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

    const { roles } = await dispatch('getInfo')

    resetRouter()

    // generate accessible routes map based on roles
    const accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true })
    // dynamically add accessible routes
    router.addRoutes(accessRoutes)

    // reset visited views and cached views
    dispatch('tagsView/delAllViews', null, { root: true })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

5、系统错误日志状态控制errLog.js

一步步看注释:

// 定义状态,logs数组
const state = {
  logs: []
}

// 定义两个改变状态的方法
// ADD_ERROR_LOG 添加日志
// CLEAR_ERROR_LOG 清除
const mutations = {
  ADD_ERROR_LOG: (state, log) => {
    state.logs.push(log)
  },
  CLEAR_ERROR_LOG: (state) => {
    state.logs.splice(0)
  }
}

// 定义两个action方法,同上,commit到mutation中执行改变
const actions = {
  addErrorLog({ commit }, log) {
    commit('ADD_ERROR_LOG', log)
  },
  clearErrorLog({ commit }) {
    commit('CLEAR_ERROR_LOG')
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

为什么要单独说一下errLog.js,因为在实际工作中,我们可以在这里,拿到错误日志,并且写入数据库或者文件

其他模块就不一一拿出来说了,后面用到,会说明

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/649200.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

yoloV5目标识别以及跟踪,功能识别动物(大象,犀牛,水牛,斑马)

yolo目标识别以及跟踪还是很强的嘞&#xff01; 一. YOLO V5我来啦 1. 前期准备 yolo V5项目下载 项目的github地址项目的gitee地址 使用git 克隆下来到项目目录下面就好 环境配置 在yolov5的文件下面有一个 requirements.txt文件,这里就是环境依赖的说明。 这里我以 vs…

DP学习之解码方法

DP学习第二篇之解码方法 91. 解码方法 - 力扣&#xff08;LeetCode&#xff09; 一. 题目解析 二. 题解 算法原理及代码 状态表示 tips: 经验题目要求。以i位置为结尾&#xff0c;。。。 dp[i]: 以i位置为结尾时&#xff0c;解码方法的总数 状态转移方程 tips: 用之前或…

5.3.2 因特网的路由协议(二)基于距离向量算法的RIP协议

5.3.2 因特网的路由协议&#xff08;二&#xff09;基于距离向量算法的RIP协议 一、RIP协议概念 RIP是Routing Information Protocol缩写&#xff0c;又称为路由信息协议&#xff0c;是最先得到应用的内部网关协议&#xff0c;RIP作为一个常在小型互联网中使用的路由信息协议…

【mmcls】mmdet中使用mmcls的网络及预训练模型

mmcls现在叫mmpretrain&#xff0c;以前叫mmclassification&#xff0c;这里为了统一称为mmcls。在基于MM框架的下游任务&#xff0c;例如检测(mmdetection)中可以使用mmcls中的backbone进行特征提取&#xff0c;但这就需要知道网络的参数以及输出特征的维度。本文简单介绍了在…

CDD诊断数据库的简单介绍

1. 什么是数据库? 数据库是以结构化方式组织的一个数据集合。 比如DBC数据库: Network nodes Display Rx Messages EngineState(0x123) 通过结构化的方式把网络节点Display里Rx报文EngineState(0x123)层层展开。这种方 式的好处是:层次清晰,结构分明,易于查找。 2. 什么…

ERROR: AddressSanitizer: heap-use-after-free on address

内存错误"heap-use-after-free"&#xff0c;这是因为在C中&#xff0c;当使用delete关键字释放对象的内存后&#xff0c;该对象仍然会保留指向已经被释放内存的指针。这个指针称为悬挂指针&#xff08;Dangling Pointer&#xff09;。如果我们试图访问已经被释放的内…

【Linux】15. 文件系统与软硬链接

1. 文件系统的引出 在之前的学习过程当中&#xff0c;我们知道当文件被打开后需要加载进内存&#xff0c;第一步为其创建struct file结构体描述其结构(操作系统需要管理被打开的文件&#xff1a;先描述再组织)&#xff0c;在通过进程当中的文件描述符指针指向文件描述符表&…

《机器学习算法竞赛实战》-chapter2问题建模

《机器学习算法竞赛实战》学习笔记&#xff0c;记录一下自己的学习过程&#xff0c;详细的内容请大家购买作者的书籍查阅。 问题建模 当参赛者拿到竞赛题目时&#xff0c;首先应该考虑的事情就是问题建模&#xff0c;同时完成基线(baseline)模型的pipeline搭建&#xff0c;从…

芯片工程师平均薪酬排第一,入行就学这几个热门专业>>>

高考已经结束&#xff0c;对于广大考生来说&#xff0c;考一个理想的分数固然重要&#xff0c;但高考志愿的填报同样事关重大&#xff0c;它决定未来几年考生的学习走向&#xff0c;也会影响到考生未来职业生涯的长远发展。目前&#xff0c;北京、江苏、河南、湖南、海南、甘肃…

Spring Boot进阶(45): Spring Boot 如何返回统一结果包装?一文教会你 | 超级详细,建议收藏

1. 前言&#x1f525; 现如今是前后端分离的时代&#xff0c;如果没有统一的返回格式&#xff0c;给前端的结果各式各样&#xff0c;估计前端小伙伴就要骂街了。我们想对自定义异常抛出指定的状态码排查错误&#xff0c;对系统的不可预知的异常抛出友好一点的异常信息。我们想让…

Java基础重点概要(部分)

为工信部第六届全国计算机信息大赛准备 &#xff0c;主要复习以下内容。 Java基础及环境&#xff1a;JDK发展历史&#xff0c;不同版本的进阶内容。Java程序的编写、编译、调试。 Java程序设计基础&#xff1a;常量和变量的概念&#xff0c;声明方式和作用域。基本数据类型的定…

基于Java学校运动会管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

C语言之指针详解(4)

目录 本章重点 1. 字符指针 2. 数组指针 3. 指针数组 4. 数组传参和指针传参 5. 函数指针 6. 函数指针数组 7. 指向函数指针数组的指针 8. 回调函数 9. 指针和数组面试题的解析 函数指针 数组指针—指向数组的指针 函数指针—指向函数的指针 函数指针 我们来看代码 #…

基于人工智能,现代数据基础架构的新兴架构

作者 Matt Bornstein、Jennifer Li和Martin Casado 摘要 现代机器学习基础设施2.0新架构&#xff1a; http://bit.ly/3AVBpV6 这个图概括了机器学习基础设施2.0的主要组成部分。它涵盖了从数据转换到模型集成的全过程。每个阶段的具体工具和技术也在括号中列出。 结构解读 …

stub实验和配置命令

拓扑 需求 将区域12设置为Stub区域&#xff0c;使区域12的路由设备不受外部链路影响(不接收4/5类LSA&#xff09;降低区域12&#xff08;末梢区域&#xff09;设备压力&#xff0c;还能让区域12的PC1与外部PC3通信 配置步骤 1&#xff09;配置接口信息 - 配置PC的IP地址 - 配置…

SpringBoot的基础配置 - yaml文件的格式以及数据读取

文章目录 SpringBoot基础配置配置文件格式yaml文件格式yaml数据读取 SpringBoot基础配置 配置文件格式 我们用修改服务器端口号来举例, 演示配置的格式 目前我们SpringBoot入门程序已经可以启动, 但是端口是使用的默认的8080 http://localhost:8080/books/1修改服务器的端口号…

CleanMyMacX4.13.4中文免费版mac电脑管家

CleanMyMac X这款软件集成清理、mac保护、速度优化维护、应用程序管理和文件管理5大功能&#xff0c;使用过程安全高效&#xff0c;用户不必担心误操作导致系统的崩溃。作为一款专业的mac电脑系统管家&#xff0c;CleanMymac X一直致力于更加智能、便捷地全方位维护我们的电脑&…

基于servlet+jsp+mysql人事工资管理系统(含实训报告)

基于servletjspmysql人事工资管理系统 一、系统介绍二、功能展示1.用户登陆2.查看个人信息3.查看个人工资、查看考勤4.查看自己所在部门5.人员信息管理6.考勤管理&#xff08;管理员&#xff09;7.工资管理&#xff08;管理员&#xff09;8.部门管理&#xff08;管理员&#xf…

批量生成,本地推理,人工智能声音克隆框架PaddleSpeech本地批量克隆实践(Python3.10)

云端炼丹固然是极好的&#xff0c;但不能否认的是&#xff0c;成本要比本地高得多&#xff0c;同时考虑到深度学习的训练相对于推理来说成本也更高&#xff0c;这主要是因为它需要大量的数据、计算资源和时间等资源&#xff0c;并且对超参数的调整也要求较高&#xff0c;更适合…

大数据处理架构Hadoop

大数据处理架构 Hadoop 概述Hadoop简介Hadoop的特性 Hadoop项目架构Hadoop的安装和使用Hadoop的安装方式Hadoop的安装配置&#xff08;单机/伪分布式&#xff09;SSH登录权限设置单机安装配置伪分布式安装配置 Hadoop集群的部署与使用Hadoop集群中有哪些节点类型集群规模要多大…