当前位置: 代码迷 >> 综合 >> 详细分析 vue-admin-template
  详细解决方案

详细分析 vue-admin-template

热度:8   发布时间:2024-02-05 12:23:43.0

1、整体效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、目录分析

一、目录结构

在这里插入图片描述

二、配置信息

vue.config.js

这里面配置了项目的基本信息: 所使用的环境、端口号、对外路径、输入文件路径等信息 , 可以看到我们使用的dev开发环境,下面将查看开发环境的配置

const port = process.env.port || process.env.npm_config_port || 9528 // dev port// All configuration item explanations can be find in https://cli.vuejs.org/config/
module.exports = {/*** You will need to set publicPath if you plan to deploy your site under a sub path,* for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,* then publicPath should be set to "/bar/".* In most cases please use '/' !!!* Detail: https://cli.vuejs.org/config/#publicpath*/publicPath: '/',outputDir: 'dist',assetsDir: 'static',lintOnSave: process.env.NODE_ENV === 'development',productionSourceMap: false,devServer: {port: port,open: true,overlay: {warnings: false,errors: true},

.env.development

在这里会标注我们后台的路径, 此时因为使用的是mock数据, 所有只是提供了一下路径而已。以及标注当前文件的类型

ENV = ‘development’ 此时便引入了与后端数据交互, 与后端的交互接口都在 api的文件家里面。

# just a flag
ENV = 'development'
# base api
VUE_APP_BASE_API = '/dev-api'

三、主要文件分析

api 文件夹

截取user.js 文件里面的一部分, 可以看到这个文件会向后端发送http请求, 但是它使用的是 /utils/request 里面的内容

先说明此文件的作用, 在这个开源框架中与后端交互使用的是 axios 组件。指定请求的路径、类型、请求参数、请求体参数, 就可以执行异步亲求了。下一步介绍 /utils/request

import request from '@/utils/request'export function login(data) {return request({url: '/vue-admin-template/user/login',method: 'post',dataparams})
}

/utils/request

首先创建一个axios的实例, 对于这个实例需要设定的有: 基本的URL、以及请求超时的。

// create an axios instance
const service = axios.create({baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url// withCredentials: true, // send cookies when cross-domain requeststimeout: 5000 // request timeout
})

第二步是添加拦截器, axios每次请求都会经过这个拦截器。 store.getters.token 首先从全局状态管理那里判断 token , 有的话就可以请求, 否则就抛出异常。并且可以清楚的看到如果有 token的话, 我们在请求的时候会得到当前的token 并且直接添加到请求头中, 以便后端得到当前登录的信息。

// request interceptor
service.interceptors.request.use(config => {// do something before request is sentif (store.getters.token) {// let each request carry token// ['X-Token'] is a custom headers key// please modify it according to the actual situationconfig.headers['X-Token'] = getToken()}return config},error => {// do something with request errorconsole.log(error) // for debugreturn Promise.reject(error)}
)

下面是对返回结果的拦截, 在这里会判断返回结果中的状态码, 根据状态码来判断这次请求的状态如何。

// response interceptor
service.interceptors.response.use(response => {const res = response.data// if the custom code is not 20000, it is judged as an error.if (res.code !== 20000) {Message({message: res.message || 'Error',type: 'error',duration: 5 * 1000})// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;if (res.code === 50008 || res.code === 50012 || res.code === 50014) {// to re-loginMessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {confirmButtonText: 'Re-Login',cancelButtonText: 'Cancel',type: 'warning'

最后将 axios的实例导出 export default service, 在这里我们看到了 store.getters.token 以及文件最上面的导入

import store from '@ /store'
store.getters.token // 下一步查看 /store 这个文件夹

/store

简单介绍此文件中几个重要的知识点

  • ? State提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储
  • ? Mutation用于修改变更$store中的数据
  • 在mutations中不能编写异步的代码,会导致vue调试器的显示出错。在vuex中我们可以使用Action来执行异步操作。
  • Getter用于对Store中的数据进行加工处理形成新的数据
    它只会包装Store中保存的数据,并不会修改Store中保存的数据,当Store中的数据发生变化时,Getter生成的内容也会随之变化
  token: state => state.user.token,

在 gettes 文件中我们看到了 token 这个标识, 其中 gettes 文件就是为了我们方便从全局状态管理中获取数据的工具, 在这里可以得到当前的 token 。

此文件主要是使用了 vuex , 而 vuex 是 vue中的全局的状态管理, 方便我们进行组件之间的数据传递。基本使用如下

this.$store.state.count // 得到store中值// 调用Acton中的异步方法 user.js 中的login 方法 , 这个是 /veew/login 文件中的代码 
this.$store.dispatch('user/login', this.loginForm).then(() => {this.$router.push({path: this.redirect || '/'})this.loading = false
})

token 相关的

  RESET_STATE: (state) => {Object.assign(state, getDefaultState())},SET_TOKEN: (state, token) => {state.token = token},

登录相关的

举例说明 login 方法, 首先 传入 {commit} 以及在方法中 commit(‘SET_TOKEN’, data.token) 这两个的作用是执行 action 中异步方法的简写, 组用就是设置 token 的值, 我们知道修改 store中的数据需要使用 Mutation 就是会调用上面的 SET_TOKEN 把 后端返回的token 保存到vuex中, 并且使用 setToken(data.token) 方法把 token写入到 cookie中 以便我们每次请求都可以带上这个 cookie , 并且能够解析出当前登录的用户 。

  // user loginlogin({commit}, userInfo) {console.log('login')const {username, password} = userInfoconsole.log("user info ->>>>" + username + "=>>>" + password)return new Promise((resolve, reject) => {login({username: username.trim(), password: password}).then(response => {const {data} = responsecommit('SET_TOKEN', data.token)console.log(data.token)setToken(data.token)resolve()}).catch(error => {reject(error)})})},

在这个文件中我们还可以观察到最上面存在组件的导入, 这就和之前的说明相匹配。

import {login, logout, getInfo} from '@/api/user'
import {getToken, setToken, removeToken} from '@/utils/auth'
import {resetRouter} from '@/router'

main.js

这个是项目的入口文件, 在这个入口文件中, 我们看到当前是使用mock数据, 并且全局挂在 element - ui 以及在vue的实例中挂载了 路由、store (vuex) , 那下一步开始讲解路由

if (process.env.NODE_ENV === 'production') {const { mockXHR } = require('../mock')mockXHR()
}// set ElementUI lang to EN
// Vue.use(ElementUI, { locale })
// 如果想要中文版 element-ui,按如下方式声明
Vue.use(ElementUI)Vue.config.productionTip = falsenew Vue({el: '#app',router,store,render: h => h(App)
})

/ router

使用vue router的第一步是需要一个路由表、以及把路由表加载到路由实例中, 最后把路由实例导出。下面就是定义的路由表, 对于路由表 中包括

  • path : 访问的路径
  • component : 此路由对于的组件
  • hidden : 是否在界面显示此路由
  • meta : 设置路由的属性, 图标之类的
  • name : 路由名字
  • children : 该路由下的子路由, 效果就是二级菜单
export const constantRoutes = [{path: '/login',component: () => import('@/views/login/index'),hidden: true,children: [{path: 'https://panjiachen.github.io/vue-element-admin-site/#/',meta: {title: 'External Link', icon: 'link'}}},{path: '/404',component: () => import('@/views/404'),hidden: true},

下面就是新建路由实例, 以及添加路由表, 导出路由。 上面介绍到了组件, 下一步解释路由对应的组件

const createRouter = () => new Router({// mode: 'history', // require service supportscrollBehavior: () => ({y: 0}),routes: constantRoutes
})const router = createRouter()// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {const newRouter = createRouter()router.matcher = newRouter.matcher // reset router
}export default router

/view/login/login.vue

组件的概念比较广泛,可以暂时理解为一个界面, 下面是登录的界面, name: ‘Login’, 定义的组件名称。 当在路由表中配置了此路由的信息后,就可以在使用中根据对应的path 来访问此路由。

<template><div class="login-container"></div>
</template>
<script>import {validUsername} from '@/utils/validate'export default {name: 'Login',data() {},watch: {},methods: {}}
</script><style lang="scss"></style>

permission.js

此文件是用来配合路由使用的, 对于vue router 而言它还附带了一些其他的信息, 比如路由守卫, 在路由守卫中我们可以在路由跳转之前来做一些事情的。

对于此项目来讲;

1、首先判断是否有token

2、没有token , 如果在白名单里面, 就直接放行, 否则就直接强制跳转登录。

3、有token , 如果是 /login 就就直接到 根目录下

4、不是 /login 就去 store 里面找 当前用户的信息, 然后在放行

const whiteList = ['/login'] // no redirect whitelistrouter.beforeEach(async(to, from, next) => {// start progress barNProgress.start()// set page titledocument.title = getPageTitle(to.meta.title)// determine whether the user has logged in//console.log(getToken())const hasToken = getToken()if (hasToken) {if (to.path === '/login') {// if is logged in, redirect to the home pagenext({ path: '/' })NProgress.done()} else {const hasGetUserInfo = store.getters.nameif (hasGetUserInfo) {next()} else {try {// get user infoawait store.dispatch('user/getInfo')next()} catch (error) {// remove token and go to login page to re-loginawait store.dispatch('user/resetToken')Message.error(error || 'Has Error')next(`/login?redirect=${to.path}`)NProgress.done()}}}} else {/* has no token*/if (whiteList.indexOf(to.path) !== -1) {// in the free login whitelist, go directlynext()} else {// other pages that do not have permission to access are redirected to the login page.next(`/login?redirect=${to.path}`)NProgress.done()}}
})

3、登录流程

一、流程分析

如果是在项目初始化的情况下, 当前的配置如下 并且使用的是 mock 数据

  • 环境 lintOnSave: process.env.NODE_ENV === ‘development’, vue.config.js 中
  • VUE_APP_BASE_API = ‘/dev-api’ .env.development 中
  • before: require(’./mock/mock-server.js’) vue.config.js 中

1、/view/login/login

这里是处理登录按钮的,点击登录之后会执行 store中的异步方法

      async handleLogin() {this.$refs.loginForm.validate(valid => {if (valid) {this.loading = truethis.$store.dispatch('user/login', this.loginForm).then(() => {this.$router.push({path: this.redirect || '/'})this.loading = false}).catch(() => {this.loading = false})} else {console.log('error submit!!')return false}})}

2、/store/modules

这里会得到输入的用户名以及密码。 并且执行 login 方法, 把返回的token , 保存到 vuex、cookie 中(在路由守卫中 / login 是白名单会直接放行、axios 的请求拦截中 添加的是一个空值)

  login({commit}, userInfo) {console.log('login')const {username, password} = userInfoconsole.log("user info ->>>>" + username + "=>>>" + password)return new Promise((resolve, reject) => {login({username: username.trim(), password: password}).then(response => {const {data} = responsecommit('SET_TOKEN', data.token)console.log(data.token)setToken(data.token)resolve()}).catch(error => {reject(error)})})},

二、请求分析

? 我们的登录请求会先经过 路由守卫判断是否存在 token, 如果不存在就会直接跳出登录界面, 路由守卫通过之后向后端发起请求, 而请求会被 axios拦截,为请求头添加上 token信息, 请求结束后 axios会拦截我们的响应信息对状态码进行判断。 一切符合就会放行,,,,,,,,

  相关解决方案