项目搭建
项目基础配置
vueCli基础配置 vue.config.js
反向代理配置
路径别名配置
配置反向代理 以及 axios的二次封装
proxy: {
// 开发时所有的请求 必须以 /api开头 (不能加源)
'/api': {
// 代理的目标服务器
target: 'https://www.fastmock.site/mock/2fffb10607d962fe159da85d0dcd9258',
// 请求时是否切换源
changeOrigin: true,
// 路径重写
pathRewrite: {
// ^/api所有请求地址 开头/api
'^/api': '/api'
/*
反向代理 必须要有一个 请求前缀,才能触发,比如 上述反向 必须 以/api开头 触发反向代理
问题?
大部分前后端分离 接口 有请求前缀 /api 如果 有的接口没有请求前缀
就需要将 请求中开始 /api 发请求去掉 不然会产生404
http://xxx.com/itemLists 真实 后端接口完整路径
配置 /api反向代理后真实发出去的地址时
target + /api重写后的值 + 路径
axios发请求地址这样写 http://xxx.com/itemLists
*/
}
}
}
axios二次封装
import axios from 'axios'
// 配置 baseURL 以及超时时间等
const request = axios.create({
/*
开发时 baseURL一般为 /api 反向代理 请求前缀
上线后:
线上服务器源+/api 一般 上线后 前端代码和后端接口代码部署同一个源下
怎么解决 axios 请求 基础源 开发和生产不一致问题
*/
baseURL: process.env.VUE_APP_BASEAPI
})
// 添加请求和响应拦截
request.interceptors.request.use(function (config) {
// 请求头添加token 做接口 token校验
return config
}, function (error) {
return Promise.reject(error)
})
request.interceptors.response.use(function (response) {
// 判断后端返回 code码 做 登录过期 未登录处理
return response
}, function (error) {
return Promise.reject(error)
})
export default request
环境变量
解决开发生产接口源不一致的问题
如何获取环境变量
process.env.具体环境变量名
vueCli(vite) 提供默认环境变量 叫 NODE_ENV 保存的是 现在代码运行环境
process.env.NODE_ENV 变量在开发环境下 值时 development在生产环境下 值时
production
1 利用 NODE_ENV 内置环境变量 来 判断开发生产
import axios from 'axios'
// 配置 baseURL 以及超时时间等
const request = axios.create({
baseURL: process.env.NODE_ENV === 'development'
? '/api'
: '生产的源+/api'
})
2 自定义环境 直接保存 开发源
vueCli中自定义环境变量语法如下
/*
项目根目录下创建两个文件
.env.development 某个环境变量在开发时的值
.env.production 某个环境变量在生产环境时的值
注意:
自定义环境变量必须以 VUE_APP_变量名开头
VUE_APP_变量名=值
定义完环境变量后重启生效
*/
后台管理常用目录
src
assets // 静态资源
api // 封装 接口函数
utils // 工具函数目录 (比如 对于 axios的二次封装)
components // 公共组件
router // 路由配置
store // vuex 配置
views // 路由组件 目录名(两个单词 大驼峰 index.vue组件名 name和目录名保持一致)
App.vue // 根组件
main.js // 入口文件
mock接口
项目流程:
项目开发时 前后端分离, 前后端同时进行开发, 问题:
前端开发时,后端接口也正在编写,前端开发时 需要 自己mock接口 (模拟接口)
模拟接口:
注意:
模拟每一个接口 多要和 后端真实接口保持一致
1 路径 (源可变)
2 请求方式和参数 保持一致
3 返回数据 结构和真实结构一样
mock接口语法
- 本地 mockjs 插件进行mock
mock:拦截ajax请求,并生成随机数据
特点:
请求并没有真的发出去(被mockjs拦截了)
基础用法:
- 安装
npm i mockjs -D
- 在线mock平台
利用mockjs语法 生成随机数据,可以真实发出请求
fastmock https://www.fastmock.site/#/
easymock
apipost
rap2.taobao.org
项目中使用import引入和 require引入区别
- import 必须是 编译前提前引入
require可以按需引入
(作业:引入一个assets中的文件 作为 一个 div背景图片) - require一般用来 引入 生产环境不需要模块
显眼(快速区分 生产依赖 非生产依赖)
注意
前后端分离 接口 一般都会有前缀 (/api)
npm 高版本安装包 报错问题
原因:
项目依赖包
dependencies 项目生产环境依赖包
devDependencies 开发依赖包
peerDependencies 所有包的依赖包
peer 包依赖包
// 强制安装
npm i 包 -S --force
npm i --force
element-plus组件库
开发中 页面接口一般会在 外部 提取 单独管理
api
itemLists.js // 以路由组件进行单独提取
cateLists.js
拆分组件
一个 路由组件所有功能 不要都在路由组件中完成 代码量过大 尤其 是 选项式 api 代码审查难度 特别大
遵循状态提升和单向数据流
组件
逻辑组件
(组件内部有很多数据要管理 处理业务 没有任何复用性)
UI组件 (复用 在多个 逻辑组件 都可以使用)
element 表单 验证
常用验证规则
- 必填验证
{
required: true,
message: '该字段必须填写', // 当验证不通过时 错误提示文本
trigger: 'blur' // 验证触发时机 默认是 blur
}
- 字符串长度验证
{
min: 3,
max: 5,
message: '该字符长度应该是3-5'
}
- 常用类型验证
{
type: 'date', // array
message: 'xx'
}
/*
string
number
boolean
method
regexp
integer
float
array
object
enum
date
url
hex
email
any
*/
- 使用正则
{
pattern: /[a-z]\w{3,8}/, // 直接写正则
message: '该字段4-9位小写字母和数字组成且首字符必须是小写字母'
}
- 自定义验证规则
{
validator: (rule, value, callback) => {
// 运行callback() 则验证通过 运行callback(new Error('验证失败'))
if (value === '小明') {
callback()
} else {
callback(new Error('必须输入小明'))
}
}
}
- 异步校验
{
asyncValidator: (rule, value) => {
return new Promise((resolve, reject) => {
if (value < 18) {
reject('too young'); // reject with error message
} else {
resolve();
}
});
},
}
// 该字段发给后端校验 校验不通过 后端 报错给前端 axios
{
asyncValidator: (rule, value) => {
return axios.get('xxxx', {
params: {
key: value
}
})
},
}
项目上传图片 文件
很多接口都需要 图片字段 字段要求传递 图片地址
? 图片只有先上传 才会有地址
假设 有5个接口都需要上传 图片(地址)
接口是这样处理的:
整个项目接口中,有一个单独的接口 一般叫 upload 专门用来上传文件的,上传后会立即返回 上传成功 文件 服务器地址
所有 需要上传文件的接口 在表单控件中新增一个 文件上传 控件, 点击文件上传时 立即上传 返回了地址,地址 合并 最终上传 表单字段中
文件上传常用场景:
1 默认自动上传 如何改成 手动上传
2 限制上传文件的 类型 以及 体积
3 上传成功图片 回显
后台管理中 excel导入导出功能
利用xlsx 实现excel导入导出
导出excel 案例
import { utils, writeFileXLSX } from 'xlsx'
function exportFile() {
const ws = utils.json_to_sheet(data);
/*
data长这样
[
{
name:'小明',
age: 10
}
]
*/
const wb = utils.book_new();
utils.book_append_sheet(wb, ws, "Data");
writeFileXLSX(wb, "导出文件名.xlsx");
}
导入 利用 element upload组件 选择文件 (input type=“file”)
<el-upload
action="#"
accept=".xlsx, .xls"
:before-upload="writeFile"
>
<el-button type="primary">
导入excel批量添加商品
</el-button>
</el-upload>
import { read, utils } from 'xlsx'
const writeFile = (file) => {
// 选择excel模板批量添加商品
// file就是 选择文件 将文件转换成 arraybuffer格式
// FileReader
const fd = new FileReader()
fd.readAsArrayBuffer(file)
// 事件 fd 读取文件是异步 读取成功 在 onload事件中触发
fd.onload = () => {
// fd.result
const wb = read(fd.result)
const data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]])
const data2 = data.map(el => (
{
itemName: el.商品名,
itemPrice: el.商品价格,
itemDesc: el.商品描述,
onSale: el.上下架
}
))
console.log(data2)
// 发送请求给 后端批量添加 商品的接口
}
return false
}
后台管理中 常用富文本编辑器
ueditor 百度 (样式老旧)
wangeditor (基于vue和react二次封装)
注意:
使用 wangeditor 基于vue封装的组件,使用的 vue3的选项式api,请见 vue2文档
quill (基于vue和react进行二次封装)
后台管理中常用 技术栈 图表(echarts) 地图(百度、高德)
x轴 类目轴
y轴 数据轴
系列:
一个图表可以有多个系列数据
使用vue3 且使用选项式api 才会遇到一个坑
charts两个问题
1 数据一般是后端返回的,请求是异步的
详见官方文档
2 后端返回的数据 和 echarts的数据一般不一致
默认 echarts x轴系列data要求的列数据
{
cate: ['袜子', '毛衣', '短裙', '围巾'],
sale: [11, 22,33,44,55],
profit: [44,23,46,68,89]
}
后端返回是行数据
[
{
item: '袜子',
sale: 11,
profit: 44
},
{
item: '毛衣',
sale: 22,
profit: 23
},
{
item: '短裙',
sale: 33,
profit: 46
},{
item: '围巾',
sale: 55,
profit: 89
}
]
解决方法:
封装行转列函数,自己将行数据转换成列数据即可 (百度)
作业:
封装函数实现 行数据转列数据
使用echarts 数据集语法
项目中使用地图
百度地图 高德
开放平台
登录地图 开放平台 控制台
创建应用
应用类型两种
服务端
百度地图提供给你的 各种接口
直接请求得到对应数据
poi搜索
(一般给后端用,前端直接发请求会涉及到跨域的问题,前端请求后端的接口,拿到数据再去请求地图服务端接口)
前台
1 提供一个地图组件 在页面上渲染
2 提供方法 做 地图交互 (地图添加标记点 做poi搜索、路线规划)
浏览器
小程序
安卓
IOS
前端使用地图 比如百度地图
1 直接使用原生百度地图
2 使用基于 vue封装的百度地图组件库
http://map.heifahaizei.com/doc/begin/use.html
后台管理中权限
登录鉴权
-
路由鉴权
当用户没有登录 是无法 访问(除了登录页) 所有路由
问题:
路由鉴权 前端判断 是否登录时 只能判断token是否存在(有安全问题) -
接口鉴权
前端在发请求时,需要将 后端登录返回的token 放到所有请求的请求头中(token access_token)
后端首先 会校验 token是否传递 是否过期(不对) 返回对应 code(200 403token没有 没有权限 401token过期)思路:
在axios请求拦截中 获取token 设置请求头,将token 定义在请求头中在响应拦截中 判断 code 如果是 401则token过期 403则未登录
角色鉴权 rabc (基于角色权限管理)
1 定义用户不同角色角色
2 不同角色分配不同权限
3 每个用户 有一个字段 role 代表当前用户的角色
实现方式有两种
- 静态角色鉴权
特点:
所有的路由侧边导航菜单是在前端定死,路由和导航 数据新增一个字段,代表当前 可以访问这个路由或者导航菜单的所有的角色,用户登录时 登录接口会返回一个 字段 role:'admin’代表当前用户的 角色
导航菜单:
filter 条件是 当前导航 roles中是否包含 当前用户的role
路由:
新增没有权限路由, 在路由前置首位中判断,当前路由的roles是否包含 当前用户的role 包含则 next
不包含 重定向没有权限这个路由
roles: [‘superAdmin’,‘admin’]{ path: 'xxx', meta: { roles: ['superAdmin','admin'] } } // 菜单 { label: '仪表盘' path: 'xxx', isMenu: true, roles: ['superAdmin','admin'], children: [] }
优缺点:
优点是 实现方式简单,不需要后端过多配合
缺点:
权限上线后是无法修改
使用场景:
适用于 角色较为固定的 中小型项目
- 动态角色鉴权
每个角色可以访问的 路由 和 导航菜单数据,都是存储在后端数据库中, 用户登录时,后端会判断登录用户的角色,根据角色返回 当前用户 可以访问路由表 和 导航菜单数组,前端动态添加 导航菜单动态添加路由
router.addRoute()
后台管理半成品模板:
vue-element-admin
步骤:
1 新增一个新的 路由?
告诉后端, 路由组件名字是什么(views/名字),meta中是否要定义数据、path一般 /名字(首字母大写改成小写)
2 路由需要 在侧边导航显示
点击设置权限管理 新增新的 导航
选择是 菜单(目录)还是导航 自己添加即可
vuex状态持久化
问题:
vuex中状态,当我们刷新浏览器时,会立即 丢失 数据回到初始化数据
原理:
在 缓存中备份一下 vuex中状态,当我们刷新时,取缓存中数据,给vuex状态赋值
备份
(
vuex某个状态,拿到值之后不会改变(登录接口返回的数据),这种同步,只需要在 请求拿到数据后,
缓存中再储存一下即可
某个状态需要改变的, 在所有mutation 只要值改变了 就要重新缓存一下当前的值
)
实现方式:
1 用户手动利用缓存备份 (推荐)
2 利用vuex插件 vuex-persister
开发中利用缓存 存储 对象或者 数组
存的时候
JSON.stringify()
取:
使用三目判断 有无缓存,有JSON.parse 没有 给 制定数据类型的初始值