相信许多人和我一样刚接触 vue 时看文档都很枯燥,看完 vue,还有 vueRouter 、vuex 、vue-cli、es6 (学不动了。。。 ) 对于看完教程之后又迟迟不能上手实际项目,只能写一些简单的小demo,这肯定和实际生产工作是有出入的,于是乎我就打算自己从零开始使用最新的技术栈搭建一个vue后台管理系统,依此加深对理论知识的学习,并增强自己的项目能力,所以希望本系列教程对你开发vue项目有所帮助。
1.项目基本简介
vue-admin-webapp 是一个后台管理 spa 页面,它基于 vue 和 element-ui 采用了最新的前端技术栈,实现了登录权限验证,动态路由生成,并使用 easy-mock 来模拟请求数据,实现了典型的业务模型案例,它可以帮你快速搭建后台管理系统模板,并根据实际的业务需求添加路由来实现企业级管理页面,相信本项目一定能帮助到你。
在线预览-github
在线预览-gitee (推荐国内用户)
目前版本基于 webpack 4.0+ 和 vue-cli 3.x 版本构建,需要 Node.js 8.9或更高版本(推荐8.11.0+),相关知识可以自行进官网进行了解
功能
登录 / 注销
页面
侧边栏
权限验证
表格操作
Excel
Excel导出
Excel导入
多级表头导出
Echarts
滑动显示更多数据
动态切换charts
map地图使用
Icons
element-icon
阿里iconfont
复制代码准备工作
在开始之前,请确保在本地安装 node 和 webpack 及 git。 本项目涉及的技术栈主要有 ES6 、vue 、vuex 、vue-router 、vue-cli 、axios 、webpack 、element-ui 、easyMock ,所以你最好提前熟悉了解这些知识,这将对你认识学习该项目有很大帮助
目录结构
下面是整个项目的目录结构
├── public # 静态资源
│ ├── favicon.ico # favicon图标
│ └── index.html # html模板
├── src # 源代码
│ ├── api # 所有请求
│ ├── assets # 图片、字体等静态资源
│ ├── components # 全局公用组件
│ ├── layout # 页面整体布局盒子
│ ├── mixins # 全局混入模块
│ ├── plugins # 全局插件部分
│ ├── router # 路由
│ ├── store # 全局store管理
│ ├── style # 全局样式
│ ├── utils # 全局公用方法
│ ├── vendor # 公用vendor(excel导入导出)
│ ├── views # views所有页面
│ ├── App.vue # 入口页面
│ ├── main.js # 入口文件 加载组件 初始化等
├── .borwserslistrc # 浏览器兼容相关
├── .env.xxx # 环境变量配置
├── .eslintrc.js # eslint 配置项
├── .gitignore.js # git忽略文件设置
├── .babelrc.config.js # babel-loader 配置
├── package.json # package.json
├── postcss.config.js # postcss 配置
└── vue.config.js # vue-cli 配置
复制代码安装
git clone [email protected]:gcddblue/vue-admin-webapp.git
cd vue-admin-webapp
npm install
npm run serve
复制代码启动完成后将打开浏览器访问 http://localhost:8080,接下来你就可以根据自己的实际需求,可以添加或修改路由,编写自己的业务代码。
2.页面架构
除去登录页外,整个页面架构由三个部分组成 头部 侧边栏 右侧内容页 在项目@/layout/index.js文件中对对这三个组件进行封装,通过点击左侧菜单切换右侧router-view 的路由更替,对应的项目文件如下
3.axios封装
在vue项目中,和后台进行请求交互这块,我们通常都会选择axios库,它是基于promise的http库,可运行在浏览器端和node.js中。在本项目中主要实现了请求和响应拦截,get,post请求封装。
配置不同环境
通过在项目中创建不同环境的文件,我这里只创建了开发和生产环境的,当然,你也可以创建基于测试的.env.test 等文件,以.env.production 为例:
ENV = ‘production’
VUE_APP_BASE_API = ‘https://www.easy-mock.com/mock/5cee951f11690b5261b75566/admin’
复制代码只要以 VUE_APP_ 开头的变量都会被 webpack.DefinePlugin 静态嵌入到客户端的包中。你可以在应用的代码中这样访问它们,例如我在@/api/index.js中初始化axios:
const $axios = axios.create({
timeout: 30000,
// 基础url,会在请求url中自动添加前置链接
baseURL: process.env.VUE_APP_BASE_API
})
复制代码通过创建api文件夹将所有接口都集中在这个文件夹中,根据不同的业务创建不同js文件,来更好的划分接口的功能,其中index.js中代码如下:
import axios from ‘axios’
import Qs from ‘qs’ // 处理post请求数据格式
import store from ‘@/store’
import router from ‘@/router’
import Vue from ‘vue’
import { Loading, Message } from ‘element-ui’ // 引用element-ui的加载和消息提示组件
const a x i o s = a x i o s . c r e a t e ( / / 设 置 超 时 时 间 t i m e o u t : 30000 , / / 基 础 u r l , 会 在 请 求 u r l 中 自 动 添 加 前 置 链 接 b a s e U R L : p r o c e s s . e n v . V U E A P P B A S E A P I ) V u e . p r o t o t y p e . axios = axios.create({ // 设置超时时间 timeout: 30000, // 基础url,会在请求url中自动添加前置链接 baseURL: process.env.VUE_APP_BASE_API }) Vue.prototype. axios=axios.create(//设置超时时间timeout:30000,//基础url,会在请求url中自动添加前置链接baseURL:process.env.VUEAPPBASEAPI)Vue.prototype.http = axios // 这里并发请求以便在组件使用this.$http.all(),具体看dashborad页面
// 在全局请求和响应拦截器中添加请求状态
let loading = null
/**
// get,post请求方法
export default {
post(url, data) {
return $axios({
method: ‘post’,
url,
data: Qs.stringify(data),
headers: {
‘Content-Type’: ‘application/x-www-form-urlencoded; charset=UTF-8’
}
})
},
get(url, params) {
return $axios({
method: ‘get’,
url,
params
})
}
}
复制代码如上,大家可以看我的注释说明,axios配置的封装是整个项目中很重要的模块,其实在不同的项目中,axios封装都大同小异,所以,只要掌握了一种技巧,下次开发新项目也就很容易完成封装这块。
4.权限验证及侧边栏
路由
路由是组织一个vue项目的关键,在对项目原型分析后,接下来的第一步就是编写路由,本项目中,主要分为两种路由,currencyRoutes 和 asyncRoutes
currencyRoutes:代表通用路由,意思就是不需要权限判断,不同角色用户都显示的页面,如:登陆页、404等
asyncRoutes: 代表动态路由,需要通过判断权限动态分配的页面,有关的权限判断的方法接下来会介绍。
路由相关配置说明:
/**
// 导航守卫
router.beforeEach(async (to, from, next) => {
document.title = getTitle(to.meta.title)
if (to.path === ‘/login’) {
next()
} else {
if (store.getters.token) {
const hasRoles = store.getters.roles.length > 0
if (hasRoles) {
next()
} else {
try {
const { roles } = await store.dispatch(‘user/_getInfo’)
const addRoutes = await store.dispatch(
‘permission/getAsyncRoutes’,
roles
)
router.addRoutes(addRoutes)
// hack method to ensure that addRoutes is complete
// set the replace: true, so the navigation will not leave a history record
next({ …to, replace: true })
} catch (error) {
Message.error(error)
}
}
} else {
next({
path: ‘/login’,
query: {
redirect: to.fullPath
}
})
}
}
})
复制代码这里我在通过addRoutes添加路由时,遇到一个bug,当切换角色时,并不能删除之前添加动态路由,所以这边重新初始化router.matcher的属性方式实现:
const creatRouter = () => {
return new Router({
routes: currencyRoutes,
scrollBehavior() {
return { x: 0, y: 0 }
}
})
}
const router = creatRouter()
// 解决addRoute不能删除动态路由问题
export function resetRouter() {
const reset = creatRouter()
router.matcher = reset.matcher
}
复制代码当我每次退出登录的时候执行resetRouter方法来初始化router对象,实现删除之前动态添加的路由。
最后通过element-ui的el-menu组件来递归遍历路由对象加载侧边栏。
5.Mock数据
身为前端开发人员,相信大家都知道Mock数据吧,它的作用主要就是伪造假数据使团队可以并行开发,本项目使用了 easy-mock 来实现接口数据的请求,大家可以去官网看下简单教程,easy-mock 它的好处就是不用像传统mock数据那样需要在项目中创建mock文件夹并拦截ajax来实现假数据请求,它是真真实实的api请求,并允许任何跨域请求,下面是本项目所有接口
其中所有接口通过创建 _res 字段来判断请求是否含有Authorzation头部字段是否含有token来判断用户是否是登陆状态,如下 getCardsData接口的配置:
{
code: 0,
data: {
vistors: ‘@integer(10000, 100000)’,
message: ‘@integer(100, 1000)’,
order: ‘@integer(0, 1000)’,
profit: ‘@integer(1000, 100000)’
},
_res: function({
_req,
Mock
}) {
if (!_req.header.authorization) {
return {
status: 401,
data: {
msg: ‘未授权’
}
}
} else {
return {
status: 200
}
}
}
}
复制代码mock数据在项目开发中能够起到推进项目进度的功效,大家可以预先和后端人员商量好,并先拿到假数据字段,然后mock自己的假数据,这样你就可以不用等后端人员开发接口而使项目卡住。一般在项目中,创建.env.development 和.env.production 文件,代表了开发和生产环境,在文件里可以定义不同环境接口的请求url
VUE_APP_BASE_API = ‘https://www.easy-mock.com/mock/5cee951f11690b5261b75566/admin’
复制代码在封装axios这样初始化
const $axios = axios.create({
// 设置超时时间
timeout: 30000,
// 基础url,会在请求url中自动添加前置链接
baseURL: process.env.VUE_APP_BASE_API
})
复制代码这样就可以自动根据不同的环境切换请求地址,不用我们一个一个的修改每一个请求接口
6.登录
通过将登录函数封装在store中,当点击登陆时,调用this.$store.dispatch(‘user/_login’, this.ruleForm) 这个action方法,当后台接口验证成功时,会返回 token 字段,前端会调用 localStroage 接口将这个 token 保存在本地,以后每次请求前通过拦截器将这个token保存在 Authorization 这个头部字段中,后台只要验证这个token就知道这个用户的信息了。还不只token的同学,可以 疯狂点击token说明 里面对http为什么要添加toekn及token介绍的都很详细。
这里我还采用了仿 geetest 行为验证,通过滑动图片来验证真人操作,其中原理利用 h5 canves绘制功能,绘制底部图片和滑块图片,然后监听mouseMove事件,当滑动block抠出的图片和初始化图片的y坐标差小于10时触发验证成功函数。
7、优化及小技巧
巧用Mixins
如果你的多个组件都用到一个或多个方法,我们可以不用每次都粘贴复制,这样岂不是很low,我们可以将这些方法封装在一个js文件中,当我的某个组件需要调用这个方法时
import aMixin from ‘@/mixins/a-mixin’
export default {
name: ‘page1’,
mixins: [newsMixin] //调用mixins属性,将aMixin这个模块的数据及方法等都添加进这个组建吧
}