Vue项目开发常用功能
Vue项目开发常用功能
vscode@配置
在根目录创建jsconfig.json(如果没有默认生成)
1 | { |
默认启动浏览器
修改package.json
1 | // "serve": "vue-cli-service serve", |
在vue.confog.js中添加
1 | devServer: { |
重置默认样式
1 | npm install --save normalize.css |
main.js引入(在自己的样式之前)
1 | import "normalize.css" |
或者在index.css中引入
1 | @import "normalize.css"; |
axios封装
创建axios.config.js管理不同环境的参数
创建axios.js/index.js管理请求拦截和响应拦截内容
根据对应的模块创建对应的文件/文件夹管理请求的接口
安装
1 | npm i axios |
案例:
axios.config.js
1 | // 根据process.env.NODE_ENV |
axios.js
1 | import axios from 'axios'; |
模块接口
1 | import { request } from './axios'; |
无感刷新Token
概述:服务器生成token的过程中,会有两个时间,一个是token失效时间,一个是token刷新时间,刷新时间肯定比失效时间长,当用户的 token 过期时,你可以拿着过期的token去换取新的token,来保持用户的登陆状态,当然你这个过期token的过期时间必须在刷新时间之内,如果超出了刷新时间,那么返回的依旧是 401。
处理流程:
- 在axios的拦截器中加入token刷新逻辑
- 当用户token过期时,去向服务器请求新的 token
- 把旧的token替换为新的token
- 然后继续用户当前的请求
1 | /** |
跨域配置
1 | devServer: { |
按需引入官网的小问题
官方网站描述的内容没有及时更新
1 | // babel.config.js |
移动端 rem 适配
postcss-pxtorem 是一款 postcss 插件,用于将单位转化为 rem
lib-flexible 用于设置 rem 基准值
一、使用 lib-flexible 动态设置 REM 基准值(html 标签的字体大小)
1、安装
1 | yarn add amfe-flexible |
2、然后在 main.js 中加载执行该模块
1 | import 'amfe-flexible' |
最后测试:在浏览器中切换不同的手机设备尺寸,观察 html 标签 font-size 的变化。
二、使用 postcss-pxtorem将 px 转为 rem
1、安装
1 | yarn add -D postcss-pxtorem |
2、然后在项目根目录中创建 postcss.config.js 文件
1 | module.exports = { |
3、配置完毕,重新启动服务
最后测试:刷新浏览器页面,审查元素的样式查看是否已将 px 转换为 rem。
注意行内样式是不能转换
Vuex持久化管理
持久化- 前端持久化-后端持久化-都是通过缓存来做
localStorage-自己写也行,也可以用插件
原理-刷新页面-所有的东西都销毁重来,Vuex 都会重来, 要保证重新初始化的时候能够读取到之前存储的数据-从缓存中读取数据
- 初始化的时候从缓存中读取
- 修改的状态的时候存入缓存
登录逻辑
- 点击登录后
- 可以选择性的添加(人机判断)
- 判断用户名/密码的前端验证
- 判断是否符合规则否则按钮无法点击
- 请求接口登录
- 成功则跳转页面保存对应的用户数据
- 失败则弹出对应的错误提示
- 验证成功后将对应的
Token保存- 分别保存到浏览器和
vuex- 保存到浏览器是防止刷新数据丢失
- 保存到
vuex是为了更好的性能
- 分别保存到浏览器和
- 选择性的在封装的
axios的请求拦截中携带Token - 通过保存的
Token判断用户的权限- 获取用户权限对应的路由权限
- 获取用户权限对应的按钮权限
- ……
- 通过路由和按钮的权限进行菜单和按钮渲染
- 菜单组件
- 如果确定了几层就可以直接写几层
- 如果不确定多少层就可以使用递归
- 按钮组件
也可以不封装- 通过v-if,直接不渲染
- 通过disabled使按钮无法点击
- 菜单组件
账号密码登录
- 表单验证
- 显示提示文字
- 登录是否可以点击
- 同意协议
可选 - 调用账号密码登录的API
- 成功:跳转页面 + 消息提示
- 失败:消息提示
短信验证登录
- 表单验证
- 显示提示文字
- 验证码是否可以发送
- 验证码的倒计时
- 同意协议
可选 - 调用验证验证码的API
- 成功:跳转页面 + 消息提示
- 失败:消息提示
QQ登录
使用QQ登录的前提
- 有一个已经备案的网站
- 进入QQ互联,登录注册
- 创建应用,提供域名、备案号、回调地址
- 审核通过后获取到应用的id和key
登录逻辑
- 点击QQ登录
- 打开登录弹窗
- 用户登录
- 登录成功返回页面
是否注册过
- 注册过、已经绑定:跳转首页
- 注册过、没有绑定:进行手机号/邮箱绑定
- 未注册:进行信息的完善、跳转首页
使用QQ登录
按钮
引用JS SDK的JavaScript文件
- ```
1
2
3
4
5
6
7
8
9
10
11
- 填入APPID和回调地址
2. 在webpack中配置
```javascript
configureWebpack:{
externals:{
qc:'QC' // 包名称:全局变量名称
}
}
- ```
在使用的地方导入
放置QQ登录按钮
1
2
3
4
5
6<span id="qqLoginBtn"></span>
<script type="text/javascript">
QC.Login({
btnId:"qqLoginBtn" //插入按钮的节点id
});
</script>默认是小窗口
- 通过审查元素复制小窗口地址
- 手动写a标签和img标签、填入地址
可以选择性的删除qc和span的代码
但是webpack的qc还是有用的,后续获取QQ信息要使用
登录
判断是否登录成功
调用获取openId的方法
请求登录的API
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// 确保QQ已经登录
if (QC.Login.check()) {
// 第三方唯一标识QQ唯一标识
QC.Login.getMe((openId) => {
unionId.value = openId
// 请求后台,做QQ登录
userQQLogin(openId).then(data => {
// 登录成功:data.result 用户信息
// 1. 存储用户信息
const { id, account, avatar, mobile, nickname, token } = data.result
store.commit('user/setUser', { id, account, avatar, mobile, nickname, token })
store.dispatch('cart/mergeCart').then(() => {
// 2. 跳转到来源页或者首页
router.push(store.state.user.redirectUrl)
// 3. 成功提示
Message({ type: 'success', text: 'QQ登录成功' })
})
}).catch(e => {
// 登录失败:没有绑定
isBind.value = false
})
})
}成功:获取用户信息等后续业务
失败:没有绑定平台
有账号未绑定
获取QQ的头像昵称等信息
1
2
3
4QC.api('get_user_info').success(res => {
avatar.value = res.data.figureurl_qq_1
nickname.value = res.data.nickname
})表单校验手机号/发送验证码
绑定账号,跳转页面
没有账号没有绑定
- 需要进行对应的表单验证
- 判断用户是否存在/两次密码是否一致
- 绑定账号
退出登录
- 清除Token的信息
- 删除本地的用户信息
- 跳转到登录页面
支付逻辑
点击去支付
判断是否选择商品
选择收货地址
电商类订单页面(内容的选择和确认订单)
外卖等选择支付的方式
发送请求
获取
url,展示二维码弹出二维码/或跳转预支付页面
短轮询(最简单粗暴就是定时器反复请求接口)
判断用户是否支付
判断是否支付成功或者超时
- 成功
- 停止定时器
- 删除购物车对应的数据
- 超时
- 停止定时器
- 提示用户支付超时
- 返回购物车/跳转超时页面
- 成功
- 前端发送信息(不要包含金额等信息,前端是不安全的,交个后端处理)
- 后台服务的标准地址+支付页面地址+订单信息+回跳地址
- 通过后端处理后返回支付宝/微信的二维码
- 同步支付结果到后台、防止支付过程中断(如果支付出现异常可以进场对账)
权限
路由权限和按钮权限
路由权限
创建路由时区分好需要权限的路由,不要一次性添加,后面匹配对应的权限筛选后添加
创建路由时可以考虑使用要加一个属性用于配合后端判断权限等级
创建路由时保存好静态路由,用于退出登录后切换账号清空路由;也可以手动刷新
1
2
3
4
5
6
7
8
9
10
11const createRouter = () => new VueRouter({
mode: 'hash',// hash带# history不带#
routes
})
// 初次创建的路由,在最后有导出
const router = createRouter()
//写一个重置路由的方法,切换用户后,或者退出时清除动态加载的路由
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // 最开始的路由赋值给最新的路由
}创建路由守卫对需要权限的路由进行拦截
1
2
3
4
5
6
7
8
9
10router.beforeEach((to, from, next) => {
// 进入的路由对象 通常判断不是login就要判断权限
if (to.path !== '/login') {
const token = localStorage.getItem('token')
!token ? next({ path: '/home' }) : next()
}
else {
next()
}
})登录后请求后端返回对应账号可使用的路由,持久化保存后进行筛选
筛选好对应账号权限的路由,遍历使用
this.$router.addRoute("Router", item)添加最后添加404路由
按钮权限
- 获取后端传递的权限等级,根据对应的规则判断权限
- 使用v-if/自定义属性/disabled等方法来设置需要权限的按钮
打印
1.使用步骤
安装
1 | npm install vue-print-nb --save |
在main.js中引入
1 | import Print from 'vue-print-nb' |
在组件的打印区域标签上加 id=”printArea”
1 | <div id="printArea"> 打印区域 <div> |
在组件的打印按钮标签上使用指令 v-print=”print”,print是配置对象
1 | <el-button v-print="print" type="primary">打印</el-button> |
在组件的data中定义print配置对象
1 | print: { |
2. 打印过滤(隐藏打印区域不需要打印的内容)
只需要在组件的打印区域里,给需要隐藏的内容的标签上添加
1 | class="noprint" |
3. 配置打印的样式
在全局样式中,新增标签,里面是打印时才生效的样式
1 | <style media="print"> |
4.处理常见的打印bug
1. 全局打印生效
- 解决打印出现空白页的问题
- 解决el-table表格内容过多,打印不全问题
- 解决作用域污染问题导致el-table序号错位
1 | <style media="print" lang="scss"> |
2. 局部打印,局限在当前组件里
在组件标签
1 | <style media="print" lang="scss"> |
注意
- 启动打印后可以通过调整设置的缩放来调整显示比例
- 可以通过设置背景图形来控制页面是否使用彩色背景
