一、项目环境搭建
1.vue-element-admin的了解和介绍

vue-element-admin 是一个后台前端解决方案,它基于 vue 和 element-ui实现。它使用了最新的前端技术栈,内置了 i18 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。
2.项目模板启动和目录介绍
2.1 git拉取基础项目模板
$ git clone https://github.com/PanJiaChen/vue-admin-template.git shop2.2 安装项目依赖
npm install #安装依赖2.3 启动项目
npm run dev #启动开发模式的服务项目运行完毕,浏览器会自动打开基础模板的登录页,如上图
2.4 目录结构
├── build # 构建相关├── mock # 项目mock 模拟数据├── public# 静态资源│ │── favicon.ico # favicon图标│ └── index.html # html模板├── src # 源代码│ ├── api # 所有请求│ ├── assets # 主题 字体等静态资源│ ├── components # 全局公用组件│ ├── icons # 项目所有 svg icons│ ├── layout # 全局 layout│ ├── router # 路由│ ├── store # 全局 store管理│ ├── styles # 全局样式│ ├── utils # 全局公用方法│ ├── vendor # 公用vendor│ ├── views # views 所有页面│ ├── App.vue # 入口页面│ ├── main.js # 入口文件 加载组件 初始化等│ └── permission.js # 权限管理│ └── settings.js # 配置文件├── tests # 测试├── .env.xxx # 环境变量配置├── .eslintrc.js # eslint 配置项├── .babelrc # babel-loader 配置├── .travis.yml # 自动化CI配置├── vue.config.js# vue-cli 配置├── postcss.config.js # postcss 配置└── package.json # package.json我们在做项目时 其中最关注的就是src目录, 里面是所有的源代码和资源, 至于其他目录, 都是对项目的环境和工具的配置。
3.API模块和请求封装模块介绍
axios的拦截器原理如下
3.1 axios拦截器
const service = axios.create3.2 请求拦截器
service.interceptors.request.use { config.headers['X-Token'] = getToken } return config }, error => { return Promise.reject })3.3 响应拦截器
service.interceptors.response.use { Message if { MessageBox./confirm/i.then => { store.dispatch.then => { location.reload }) }) } return Promise.reject) } else { return res } }, error => { Message return Promise.reject })3.4 api模块的单独封装
import request from '@/utils/request'export function login { return request}export function logout { return request}二、登录模块
1.设置固定的本地访问端口和网站名称
1.1 本地服务端口:在 vue.config.js 中进行设置
vue.config.js 就是vue项目相关的编译,配置,打包,启动服务相关的配置文件,它的核心在于webpack,但是又不同于webpack,相当于改良版的webpack。 在项目下, 我们发现了 .env.development 和 .env.production 两个文件 development => 开发环境 production => 生产环境 当我们运行npm run dev进行开发调试的时候,此时会加载执行 .env.development 文件内容 当我们运行npm run build:prod进行生产环境打包的时候,会加载执行 .env.production 文件内容
1.2 网站名称
网站名称实际在configureWebpack选项中的name选项,通过阅读代码,我们会发现name实际上来源于src目录下的 settings.js 文件。
module.exports = { title: '小优电商后台管理系统', sidebarLogo: true}2.登录页面的基础布局
2.1 设置头部背景
2.2 设置背景图片
.login-container { background-image: url; background-position: center; background-size: 100% 100%;}3.登录表单的校验
3.1 用户名和密码的校验
loginRules: { username: [{ required: true, trigger: 'blur', validator: validateUsername }], password: [ { required: true, trigger: 'blur' }, { min: 6, max: 12, trigger: 'blur', message: '密码长度应该在6-12位之间' } ]},3.2 关于修饰符
@keyup.enter属于按键修饰符,如果我们想监听在按回车键的时候触发,可以如下编写
4.Vue-Cl.i配置跨域代理
4.1 为什么会出现跨域?
当下,最流行的就是前后分离项目,也就是前端项目和后端接口并不在一个域名之下,那么前端项目访问后端接口必然存在跨域的行为.
4.2 解决开发环境的跨域问题
开发环境的跨域,也就是在vue-cli脚手架环境下开发启动服务时,我们访问接口所遇到的跨域问题,vue-cli为我们在本地开启了一个服务,可以通过这个服务帮我们代理请求,解决跨域问题
proxy: { '/api/private/v1/': { target: 'http://127.0.0.1:8888', // 跨域请求的地址 changeOrigin: true // 只有这个值为true的情况下 才表示开启跨域 }}5.封装单独的登录接口
export function login { return request}6.封装Vuex的登录Action并处理token
6.1 实现store/modules/user.js基本配置
// 状态const state = {}// 修改状态const mutations = {}// 执行异步const actions = {}export default { namespaced: true, state, mutations, actions}6.2 设置 token 的共享状态
const state = { token: null}6.3 操作 token
在 utils/auth.js 中,基础模板已经为我们提供了获取 token ,设置 token ,删除 token 的方法,可以直接使用
const TokenKey = 'xiaoyou'export function getToken { return localStorage.getItem}export function setToken { return localStorage.setItem}export function removeToken { return localStorage.removeItem}6.4 初始化token状态 - store/modules/user.js
import { getToken, setToken, removeToken } from '@/utils/auth'const state = { token: getToken // 设置token初始状态 token持久化 => 放到缓存中}6.5 提供修改token的mutations
const mutations = { setToken { state.token = token // 设置token 只是修改state的数据 123 =》 1234 setToken // vuex和 缓存数据的同步 }, removeToken { state.token = null // 删除vuex的token removeToken // 先清除 vuex 再清除缓存 vuex和 缓存数据的同步 }}6.6 封装登录的Action
登录action要做的事情,调用登录接口,成功后设置token到vuex,失败则返回失败
const actions = { async login { const result = await login // 实际上就是一个promise result就是执行的结果 if { context.commit } }}6.7 区分axios在不同环境中的请求基础地址
为什么会有环境变量之分 如图 可以在 .env.development 和 .env.production 定义变量,变量自动就为当前环境的值 基础模板在以上文件定义了变量VUE_APP_base_API,该变量可以作为axios请求的baseURL 在模板中,两个值分别为/dev-api 和 /prod-api
6.8 处理axios的响应拦截器
service.interceptors.response.use { return data } else { Message.error // 提示错误消息 return Promise.reject) }}, error => { Message.error // 提示错误信息 return Promise.reject // 返回执行错误 让当前的执行链跳出成功 直接进入 catch})三、主页模块
1.主页的左侧导航样式
左侧导航组件的样式文件 styles/siderbar.scss
1.1 设置左侧导航背景图片
.scrollbar-wrapper { background: url no-repeat 0 100%;}1.2 显示左侧logo图片 src/setttings.js
module.exports = { title: '小优电商后台管理系统', fixedHeader: false, sidebarLogo: true // 显示logo}1.3 设置头部图片结构 src/layout/components/Sidebar/Logo.vue
ink key="collapse" to="/">
ink>
2.设置头部内容的布局和样式
需要把页面设置成如图样式
2.1 头部组件位置 layout/components/Navbar.vue
北京小优智慧城市科技有限公司 V1.0
2.2 右侧下拉菜单设置
pdown trigger="click">
管理员
ink to="/"> 首页 ink>项目地址 退出登录
3. 存储用户信息
3.1 新增变量 userInfo action src/store/modules/user.js
state: { token: getToken, userInfo: {} // 用于存储用户对象信息},3.2 设置和删除用户资料 mutations
// 设置用户信息setUserInfo { state.userInfo = userInfo},// 删除用户信息removeUserInfo { state.userInfo = {}}3.3 建立用户名的映射 src/store/getters.js
const getters = { token: state => state.user.token, username: state => state.user.userInfo.username}export default getters3.4 将头部菜单中的名称换成真实的用户名
{ { username }}
4.自定义指令
全局注册自定义指令语法 - 获取焦点指令
Vue.directive { console.log el.children[0].focus }})在登录组件中使用此指令
5. 实现登出功能
5.1 登出 action src/store/modules/user.js
logout { // 删除token context.commit // 不仅仅删除了vuex中的 还删除了缓存中的 // 删除用户资料 context.commit // 删除用户信息}5.2 mutation

removeToken { state.token = null // 将vuex的数据置空 removeToken // 同步到缓存},removeUseInfo { state.userInfo = {}}5.3 头部菜单调用 action src/layout/components/Navbar.vue
async logout { await this.$store.dispatch // 这里不论写不写 await 登出方法都是同步的 this.$router.push // 跳到登录}6.Token失效的主动介入
6.1 流程图转化代码
src/utils/request.js
const timeKey = 'hrsaas-timestamp-key' // 设置一个独一无二的key// 获取时间戳export function getTimeStamp { return cookies.get}// 设置时间戳export function setTimeStamp { cookies.set)}src/utils/request.js
import axios from 'axios'import store from '@/store'import router from '@/router'import { Message } from 'element-ui'import { getTimeStamp } from '@/utils/auth'const TimeOut = 3600 // 定义超时时间const service = axios.create// 请求拦截器service.interceptors.request.use { // 只有在有token的情况下 才有必要去检查时间戳是否超时 if ) { // 如果它为true表示 过期了 // token没用了 因为超时了 store.dispatch // 登出操作 // 跳转到登录页 router.push return Promise.reject) } config.headers['Authorization'] = store.getters.token } return config // 必须要返回的}, error => { return Promise.reject})// 响应拦截器service.interceptors.response.use { return data } else { // 业务已经错误了 还能进then 不能 ! 应该进catch Message.error // 提示错误消息 return Promise.reject) }}, error => { Message.error // 提示错误信息 return Promise.reject // 返回执行错误 让当前的执行链跳出成功 直接进入 catch})// 超时逻辑 是否大于 时间差function IsCheckTimeOut { var currentTime = Date.now // 当前时间戳 var timeStamp = getTimeStamp // 缓存时间戳 return / 1000 > TimeOut}export default service6.2 同理,在登录的时候,如果登录成功,设置时间戳
async login { const result = await login // 实际上就是一个promise result就是执行的结果 context.commit setTimeStamp // 将当前的最新时间写入缓存}四、路由和页面
因为复杂中台项目的页面众多,不可能把所有的业务都集中在一个文件上进行管理和维护,并且还有最重要的,前端的页面中主要分为两部分,一部分是所有人都可以访问的, 一部分是只有有权限的人才可以访问的,拆分多个模块便于更好的控制
1.新建路由
在 router 目录下新建目录 modules,在此目录中新建各个路由模块 路由模块目录结构
2.设置每个模块的路由规则
// 导出属于用户的路由规则import Layout from '@/layout'export default { path: '/user', // 路径 name: '', // 给路由规则加一个name component: Layout, // 组件 // 配置二级路的路由表 children: [{ path: '', // 这里当二级路由的path什么都不写的时候 表示该路由为当前二级路由的默认路由 name: 'user', // 给路由规则加一个name component: => import, // 路由元信息 其实就是存储数据的对象 我们可以在这里放置一些信息 meta: { title: '用户管理' // meta属性的里面的属性 随意定义 } }]}3.静态路由和动态路由临时合并,形成左侧菜单
什么叫临时合并? 动态路由是需要权限进行访问的,但是权限的动态路由访问是很复杂的,我们可以先将 静态路由和动态路由进行合并,不考虑权限问题,后面再解决这个问题路由主文件 src/router/index.js
// 引入多个模块的规则import Layout from '@/layout'import userRouter from './modules/user'import roleRouter from './modules/role'import rightsRouter from './modules/right'import goodsRouter from './modules/goods'import categoryRouter from './modules/category'import reportsRouter from './modules/report'// 动态路由export const asyncRoutes = [ userRouter, roleRouter, rightsRouter, goodsRouter, categoryRouter, reportsRouter]const createRouter = => new Router => , // 管理滚动行为 如果出现滚动 切换就让 让页面回到顶部 routes: [...constantRoutes, ...asyncRoutes]})五、内容模块
1.过滤器解决时间格式的处理
Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 。过滤器应该被添加在 Javascript 表达式的尾部,由“管道”符号指示:
{ {obj.row.timeOfEntry | 过滤器}} 安装 moment
npm i moment编写过滤器函数
import moment from 'moment'export function formatTime { return moment.format}在 main.js 中全局注册过滤器
import * as filters from '@/filters'Object.keys.forEach})2.新增用户
在 views/user 目录下新建一个弹层组件 src/views/user/components/add-user.vue
取 消 确 定 父组件中引用,弹出层
import AddUser from './components/add-user'点击 新增用户 按钮,弹出弹出层
新增用户 点击按钮展示弹出层的关键,就是设置组件中 el-dialog 组件中的如下属性的值
:visible.sync="dialogVisible"按钮在父组件,变量 dialogVisible在子组件,如何改变? 可以在子组件中的 props 中新建属性
dialogVisible然后父组件中为其赋值
最后在父组件的 data 中定义变量
addDialogVisible:false但是上面的解决方案有一个问题:点击对话框右上角的 X ,或者“取消”按钮,或者点击其他区域关闭对话框时,会抛出如下错误 **错误原因:**进行上面的几个操作时,会导致自动修改 props 中的 dialogVisible 变量的值,但这是不允许的 **解决方案:**参考上面的实现,直接在父组件中操作子组件中的 data 变量的值
3.用户导入组件封装
3.1 excel导入功能需要使用npm包 xlsx,所以需要安装xlsx 插件
$ npm i xlsx3.2 将vue-element-admin提供的导入功能新建一个组件,位置:src/components/UploadExcel
3.3 注册全局的导入excel组件
import CommonTools from './CommonTools'import UploadExcel from './UploadExcel'export default { install { Vue.component // 注册工具栏组件 Vue.component // 注册导入excel组件 }}3.4 新建一个公共的导入页面,挂载路由 src/router/index.js
{ path: '/import', component: Layout, hidden: true, // 隐藏在左侧菜单中 children: [{ path: '', // 二级路由path什么都不写 表示二级默认路由 component: => import }]},3.5 创建import路由组件 src/views/import/index.vue
3.6 获取导入的excel数据, 导入excel接口
async success { // 如果是导入用户 const userRelations = {'入职日期': 'create_time','手机号': 'mobile','用户名': 'username','密码': 'password','邮箱': 'email','部门':'部门' } const arr = [] results.forEach.forEacharr.push }) await importUser // 调用导入接口 this.$router.back}六、语言、主题和全屏切换
1.全屏插件的引用
第一步,安装全局插件screenfull
$ npm i screenfull第二步,封装全屏显示的插件src/components/ScreenFull/index.vue
第三步,全局注册该组件 src/components/index.js
import ScreenFull from './ScreenFull'Vue.component // 注册全屏组件第四步,放置于layout/navbar.vue中
.right-menu-item { vertical-align: middle;}2.动态主题的设置
第一步, 封装颜色选择组件 ThemePicker 代码地址:@/components/ThemePicker
import ThemePicker from './ThemePicker'Vue.component第二步, 放置于layout/navbar.vue中
3.多语言实现
第一步,我们需要首先国际化的包
$ npm i vue-i18n第二步,需要单独一个多语言的实例化文件 src/lang/index.js
import customZH from './zh' // 引入自定义中文包import customEN from './en' // 引入自定义英文包Vue.use // 全局注册国际化包export default new VueI18n || 'zh', // 从cookie中获取语言类型 获取不到就是中文 messages: { en: { ...elementEN, // 将饿了么的英文语言包引入 ...customEN }, zh: { ...elementZH, // 将饿了么的中文语言包引入 ...customZH } }})第三步,在main.js中对挂载 i18n的插件,并设置element为当前的语言
Vue.use => i18n.t})new Vue})第四步,在左侧菜单应用
第五步,封装多语言组件 src/components/lang/index.vue
中文 en 第六步,在Navbar组件中引入
七、打包上线
1.打包之前的路由模式
hash模式 : #后面是路由路径,特点是前端访问,#后面的变化不会经过服务器
history模式:正常的/访问模式,特点是后端访问,任意地址的变化都会访问服务器
改成history模式非常简单,只需要将路由的mode类型改成history即可
const createRouter = => new Router => , // 管理滚动行为 如果出现滚动 切换就让 让页面回到顶部 routes: [...constantRoutes] // 改成只有静态路由})2.webpack排除打包
先找到 vue.config.js, 添加 externals 让 webpack 不打包 xlsx 和 element
externals: { 'vue': 'Vue', 'element-ui': 'ELEMENT', 'xlsx': 'XLSX' }3.CDN文件配置
const cdn = { css: [ // element-ui css 'https://unpkg.com/element-ui/lib/theme-chalk/index.css' // 样式表 ], js: [ 'https://unpkg.com/vue/dist/vue.js', 'https://unpkg.com/element-ui/lib/index.js', 'https://cdn.jsdelivr.net/npm/xlsx@0.16.6/dist/jszip.min.js', 'https://cdn.jsdelivr.net/npm/xlsx@0.16.6/dist/xlsx.full.min.js' ]}但是请注意,这时的配置实际上是对开发环境和生产环境都生效的,在开发环境时,没有必要使用CDN,此时我们可以使用环境变量来进行区分
let cdn = { css: [], js: [] }// 通过环境变量 来区分是否使用cdnconst isProd = process.env.NODE_ENV === 'production' // 判断是否是生产环境let externals = {}if { // 如果是生产环境 就排除打包 否则不排除 externals = { // key / value 'vue': 'Vue', // 后面的名字不能随便起 应该是 js中的全局对象名 'element-ui': 'ELEMENT', // 都是js中全局定义的 'xlsx': 'XLSX' // 都是js中全局定义的 } cdn = { css: [ 'https://unpkg.com/element-ui/lib/theme-chalk/index.css' // 提前引入elementUI样式 ], // 放置css文件目录 js: [ 'https://unpkg.com/vue/dist/vue.js', // vuejs 'https://unpkg.com/element-ui/lib/index.js', // element 'https://cdn.jsdelivr.net/npm/xlsx@0.16.6/dist/xlsx.full.min.js', // xlsx 相关 'https://cdn.jsdelivr.net/npm/xlsx@0.16.6/dist/jszip.min.js' // xlsx 相关 ] // 放置js文件目录 }}4.注入CDN文件到模板
之后通过 html-webpack-plugin注入到 index.html之中:
config.plugin.tap
找到 public/index.html。通过你配置的CDN Config 依次注入 css 和 js。
<% for { %> ink rel="stylesheet" href="<%=css%>"> <% } %><% for { %> <% } %> 最后,进行打包
$ npm run build:prod,https://blog.csdn.net/chuenst/article/details/117065028


