本文是一篇我在学习vue-admin-template项目时的笔记,可以帮助读者快速掌握该项目的核心思想
vue-admin-template是什么?
- 是一款基于Vue2的极简后台管理系统,只含前端。
- 只包含了 Element UI & axios & iconfont & permission control & lint,这些搭建后台必要的东西。
- 项目作者以及地址:https://github.com/PanJiaChen/vue-admin-template
背景
- vue-admin-template这个项目很适合初学者学习
- 因为它足够的简单,设计清晰,可以帮助初学者快速建立基于Vue的项目概念和一般项目的设计思想。可以基于该项目,快速构建起一个后台管理管理系统(前端)
- 我在学习这个项目的过程中,对于一些我不是很熟悉的技术,需要在源码上写一些注释 ,对于作者为什么这么设计、代码为什么这样写 ,也会写一些我的思考、设计说明
- 所以我克隆了该项目,将我的代码注释提交于Github,我对项目的一些思考与设计说明记录在本文中
强烈建议读者先阅读原作者的ReadMe
本文内容导览
克隆项目
Source Code
- 原作者:https://github.com/PanJiaChen/vue-admin-template/
- 我在原作者的源码上添加了用于学习的注释:https://github.com/HackyleShawe/vue-admin-template_4_learn
原作者提供的Demo
检查项目的依赖源
- 获取:npm config get registry
- 配置:npm config set registry https://registry.npm.taobao.org
依赖安装:进入项目根目录,执行:npm install
项目结构
├── build // 构建相关
├── config // 配置相关
├── src // 源代码
│ ├── api // 所有请求
│ ├── assets // 主题 字体等静态资源
│ ├── components // 全局公用组件
│ ├── directive // 全局指令
│ ├── filtres // 全局 filter
│ ├── icons // 项目所有 svg icons
│ ├── lang // 国际化 language
│ ├── mock // 项目mock 模拟数据
│ ├── router // 路由
│ ├── store // 全局 store管理
│ ├── styles // 全局样式
│ ├── utils // 全局公用方法
│ ├── views // 具体页面
│ ├── App.vue // 入口页面
│ ├── main.js // 入口 加载组件 初始化等
│ └── permission.js // 权限管理
├── static // 第三方不打包资源
└── package.json // 依赖管理
components
- 放置的都是全局公用的一些组件,如上传组件,富文本等等
- 一些页面级的组件建议还是放在各自views文件下,方便管理
views 和 api
- 根据业务模块来划分 views,并且 将views 和 api 两个模块一一对应,从而方便维护
- 一些全区公用的api模块,如七牛upload,remoteSearch等等,这些单独放置就行
封装axios
axios使用步骤
- 配置axios的全局参数,初始化axios
- 请求、响应拦截器
- 写GET/POST/PUT/PATCH/DELETE请求
定义axios
import axios from 'axios'
import { Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
// 创建axios实例
const service = axios.create({
baseURL: process.env.BASE_API, // api的base_url
timeout: 5000 // 请求超时时间
})
// request拦截器::从Cookie中获取token,放在请求头里
service.interceptors.request.use(config => {
// Do something before request is sent
if (store.getters.token) {
config.headers['X-Token'] = getToken() // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
}
return config
}, error => {
// Do something with request error
console.log(error) // for debug
Promise.reject(error)
})
// respone拦截器::根据后端定义的响应状态码,判断此次请求是否响应成功
service.interceptors.response.use(
response => response,
/**
* 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
* 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
*/
// const res = response.data;
// if (res.code !== 20000) {
// Message({
// message: res.message,
// type: 'error',
// duration: 5 * 1000
// });
// // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
// if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
// confirmButtonText: '重新登录',
// cancelButtonText: '取消',
// type: 'warning'
// }).then(() => {
// store.dispatch('FedLogOut').then(() => {
// location.reload();// 为了重新实例化vue-router对象 避免bug
// });
// })
// }
// return Promise.reject('error');
// } else {
// return response.data;
// }
error => {
console.log('err' + error)// for debug
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
})
export default service
使用axios
import request from '@/utils/request'
//使用
export function getInfo(params) {
return request({
url: '/user/info',
method: 'get',
params
});
}
webpack-alias
- 当项目逐渐变大之后,文件与文件直接的引用关系会很复杂,这时候就需要使用alias 了。
- 有的人喜欢alias 指向src目录下,再使用相对路径找文件
- @ 是 webpack 的 alias ,代表当前项目的src目录
- 在Vue项目配置文件config.js中定义alias
页面结构Layout
- 在src/layout/目录下定义页面的主体结构
- 在src/router/中的每个路由定义为:
-
- 将每个顶级路由的路由页面为:src/layout;
- 每个子路由的路由页面为:子路由的页面
项目主页:src/layout/index.vue
- vue-element-admin 中大部分页面都是基于这个 layout 的,除了个别页面如:login , 404, 401 等页面没有使用该layout。
- 等价于其他项目中的vue组件
- 如果你想在一个项目中有多种不同的layout也是很方便的,只要在一级路由那里选择不同的layout组件就行。
src/layout/components/AppMain.vue
- 功能:在vue组件中展示子路由页面
- <router-view>为子路由的占位符,<keep-alive>用于保存切换了Tab页后依然保存了上个页面上的数据,配合页面的 tabs-view 标签导航使用
左侧导航栏Sidebar
@/layout/components/sidebar/index.vue
Header
@/layout/components/Navbar.vue
多级导航/路由
什么是多级路由
如何实现多级路由:src/router/index.js
store
vuex
- 数据存储、传递工具
- 是专门为 Vue 开发的状态管理方案,我们可以把需要在各个组件中传递使用的变量、方法定义在这里
使用步骤
- 挂载Vuex,定义Store模型:src/store/index.js
- 加载Store,在src/main.js中导入
- 放入数据:$store.commit(mutations函数名,参数)
- 读取数据:$store.state.State中的数据名
store的基本结构
- state:要全局共享的属性,全局只存在一份
- getter:实时监听state属性的变化,并返回
- mutation:提供更改state中的属性的方法
- action:一些业务代码,并且可以提交用于mutation,目的还是为了更改state中的值
store/index.js
- vuex的入口文件
- 模块化管理vuex,引入其他的vuex组件JS文件
store/getters.js
- 将store/modules中的所有JS文件中的state属性值聚合
- 提供类似于getter的操作,实时获取整个vuex中的所有属性
store/modules模块化管理vuex
- app.js:全局存储共享本个项目的全局配置信息
- settings.js:全局存储共享本个项目的自定义配置项
- user.js:全局存储共享用户的登录信息(用户名称、token、头像URL)
登录
- 登录(认证)的主要思路:
- 当用户填写完账号和密码后向后端验证是否正确,验证通过之后,后端会返回一个token,拿到token之后(我会将这个token存贮到cookie中,保证刷新页面后能记住用户登录状态)
- 前端会根据token再去后端请求一个 user_info 的接口来获取用户的详细信息(如用户权限,用户名等等信息)。
- 权限验证的主要思路:根据后端返回的当前用户的role,动态地算出其对应有权限的路由,通过 addRoutes 动态挂载这些路由。
登录页:src/views/login/index.vue
- 一个表单:用户名输入框、密码输入框、提交按钮
- 在向服务端提交之前对账号和密码做一次简单的规则校验
- 将登录按钮上绑上click事件,点击登录之后向服务端提交账号和密码进行验证
为什么要将调用登录API的动作代码放于store/modules/user.js中?
- 使用vuex来全局共享用户成功的登录信息
- 为了便于将登录成功的用户信息塞入veux,直接在store的代码中定义调用后端的用户登录、获取登录的用户信息、登出(清空vuex中的信息)的业务代码
store/modules/user.js的action函数
- 登录:请求后端接口;成功后将token信息存储Cookie中
- 获取用户信息:请求后端接口,获取用户的信息,填充到vuex
- 登出:请求后端接口,移除本地Cookie中的Token,清除动态加载的路由,请求vuex中的数据
路由前置拦截器(router.beforeEach)
- 每次路由都判断一下Cookie里有没有token
- 如果没有跳转到登录页面
- 如果有判断一下Vuex有没有用户信息:没有用户信息:请求后端接口获取;有用户信息:路由到想要的页面
- 实现:src/permission.js
为什么不把用户信息也存放于Cookie,而每次都要向后端获取?
- 保证获取到最新的用户信息,最关键的获取的最新的用户权限,通过用户权限动态挂载路由页面。
- 假设这样一种场景,你在公司电脑上修改了权限,然后你用家用电脑登录,权限还是没有变化,要等待Cookie失效后,你家用电脑上的权限才会重新请求后端获取。
- 当然如果是做了单点登录得功能的话,用户信息存储在本地也是可以的。当你一台电脑登录时,另一台会被提下线,所以总会重新登录获取最新的内容。
Name:
Email:
Link: