一. 基础项目搭建
1. 参考这篇文章:https://mp.csdn.net/mp_blog/creation/editor/132351560
2. 安装Ant-design-vue
npm i --save ant-design-vue@1
2. 安装axios
npm i axios
3. 在main.js文件中引入依赖,并使用
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css';
Vue.config.productionTip = false
new Vue({
router,
store,
Antd,
render: h => h(App)
}).$mount('#app')
4. 在vue.config.js中关掉lintOnSave
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: false
// devServer: {
// client: {
// overlay: false
// }
// }
})
二. 项目实战
1. 绘制登录页面
简单的页面绘制完成
调用后端登录接口,使用axios:
handleSubmit(e) {
let user = this.formInline.user
let pwd = this.formInline.password
axios.post('http://192.168.220.130:8080', {
user, pwd
}).then(({ data }) => {
console.log(data);
})
},
调用的时候,因为跨域问题报错了
只需在vue.config.js中配置以下代理就可以了,即用/api替代http://192.168.220.130:8080,post请求的url改成http://localhost:8081/api即可
注意:这个接口是我本地的后端接口,小伙伴们也可以自己写一个简单的后端接口
devServer: {
proxy: {
'/api': {
target: 'http://192.168.220.130:8080',
pathRewrite: {
'^/api': ''
}
}
}
}
跨域问题解决之后,接口就调通了
2. 封装axios接口api
由于接口请求的方式都是一样的,每次调用接口都要写重复代码,不好管理,因此将接口的调用方式做个封装,参考:axios中文文档 · axios中文文档 · 看云 (kancloud.cn)
/utils/request.js 中写以下调用接口代码
import axios from "axios";
// 初始化axios实例
const instance = axios.create({
baseURL: 'http://localhost:8081/api',
timeout: 20000,
});
//get方法
export const $get = async (url, params) => {
let { data} = await instance.get(url, {
params
})
return data
}
//post方法
export const $post = async (url, params) => {
let { data } = await instance.post(url, params)
return data
}
//put方法
export const $put = async (url, params) => {
let { data } = await instance.put(url, params)
return data
}
//delete方法
export const $delete = async (url, params) => {
let { data } = await instance.delete(url, {
params
})
return data
}
/api/api.js 在业务层面封装一层api
import { $post } from "@/utils/request";
// 登录api
export const $login = async (params) => {
let data = $post('login', params)
console.log(data);
}
页面:
methods: {
handleSubmit(e) {
let user = this.formInline.user
let pwd = this.formInline.password
$login(user, pwd)
},
3. md5加密 + 保存token
前端调用接口传参时,密码在浏览器可以被抓取,是不安全的,因此需要加密
3-1 安装md5库
npm install js-md5
3-2 引入依赖并使用
import md5 from 'js-md5'
params.password = md5(params.password)
可以看到,浏览器看到的密码是加密过的
3-3 登录成功之后,会返回令牌token,之后无论哪个请求都会带着这个token访问
返回的menus代表不同的账号登录成功之后,可访问的功能列表
3-4 登录成功或失败,加提示框
3-5 存储token信息
登录成功之后,需要用sessionStorage将token信息保存到浏览器的缓存中,而且之后的每个请求需要携带这个token,那么在request.js中实现这个需求:
// 将token信息,添加到请求头
export const $setToken = (token) => {
instance.defaults.headers.common['token'] = token;
}
注意:存在一个问题,登录成功之后,再次发起请求之前页面刷新了,token信息就没有了,也就无法携带了,这时需要在main.js中加token,因为刷新会执行main.js文件
//刷新时,检查是否需要更新token
let token = sessionStorage.getItem('token')
if (token) {
$setToken(token)
}
4. 登录成功之后跳转
用户登录成功之后,需要跳转到布局页,新建布局页/views/Layout.vue
//跳转到布局页
this.$router.push('/layout')
4-1 导入svg图标文件,参考:iconfont-阿里巴巴矢量图标库
怎么使用,参考:vue2如何使用svg_vue2中使用svg_大宁宁吖的博客-CSDN博客
后续再来具体实现
4-2 加一个导航栏
5. 动态渲染侧边栏菜单
将接口返回的菜单信息存储于sessionStorage中,然后取出,在页面渲染
//缓存菜单信息
sessionStorage.setItem('menus', JSON.stringify(menus))
created: function () {
let menus = JSON.parse(sessionStorage.getItem('menus'))
this.menus = menus
}
<a-sub-menu v-for="(item, index) in menus" :key="index">
<span slot="title"><a-icon type="user" /><span>{{ item.title }}</span></span>
<a-menu-item v-for="(itemChild, indexChild) in item.children" :key="index + '-' +
indexChild">
{{ itemChild.title }}
</a-menu-item>
</a-sub-menu>
6. 自动登录+退出系统
6-1 自动登录
若缓存中用户信息不为空,则自动登录;若用户信息为空,不管哪个页面都要跳转到登录页面
router.beforeEach((to, from, next) => {
console.log(to);
if (to.path === '/layout') {
let user = sessionStorage.getItem('user')
if (!user) {
router.push('/')
}
}
else if (to.path === '/') {
let user = sessionStorage.getItem('user')
if (user) {
router.push('/layout')
}
}
next()
})
6-2 退出系统
exit: function () {
sessionStorage.clear();
localStorage.clear();
this.$router.push('/')
}
7. 根据权限动态加载路由
mounted: function () {
const that = this;
this.menus.forEach(r => {
r.children.forEach(m => {
console.log(m.component);
that.$router.addRoute('layout', {
path: m.path,
name: m.name,
component: () => import('@/views/' + m.component + '.vue')
})
})
})
}
注意:存在一个问题,当 http://localhost:8081/#/carInfo
刷新的时候页面不生效了,在main.js中重新写一份代码就可以了