记账app_12_登录鉴权与自制Mock系统
Contents
1 登录鉴权与路由守卫
1.1 登录跳转
-
return_to
属性标识了登录成功后所要返回的路由路径,有三种途径可以实现return_to-
localStorage
-
1 2
const returnTo = localStorage.getItem('return_to') router.push(returnTo || '/')
-
-
状态管理(刷新会失效)
-
queryString
,即/sign_in?return_to=/tags
-
1 2 3
router.push('/sign_in?return_to='+ encodeURIComponent(route.fullpath)) const returnTo = route.query.return_to?.toString() router.push(returnTo || '/')
-
-
-
记录跳过欢迎页的状态
- 只要用户第一次跳过欢迎页,那么后面的欢迎页就自动跳过了
- How:需要在
localStorage
中定义SkipFeatures
状态,一般值为时间戳,以确保用户能看到最新的广告(呸) - When:当用户点击跳过或完成按钮时
-
欢迎(广告)页需要添加路由守卫。当用户访问欢迎页路由时,如果SkipFeatures状态存在,那么自动跳转到首页
1.2 路由守卫
- src/config/routes.ts
|
|
1.3 登录检查
- 利用路由守卫,对记账等业务页面进行登录检查,否则跳转到登录页面
- 以/items为例
|
|
- 登录后的每次请求,都应该将jwt放到请求头中
|
|
- 对于除了
/
、/welcome
和/sign_in
其他路由,都需要添加路由守卫来验证权限,出现大量重复的代码 - 因此鉴权可以写在全局的路由守卫上
- 然后少数几个路由作为鉴权守卫的白名单
|
|
-
问题:每次路由跳转都会请求当前用户,非常浪费资源
- 解决:可以把请求的promise提取到最外层,只在第一次访问时请求,后面只是读取这个promise中的值
-
问题:在登录后应该刷新当前用户,即刷新promise
- 解决:封装me.ts,提供promise和refreshMe等接口
-
最终方案
- src/main.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14
... fetchMe(); router.beforeEach((to, from) => { for (const key in whiteList) { const value = whiteList[key]; return (value === "exact" && to.path === key) || (value === "startsWith" && to.path.startsWith(key)) } return mePromise?.then( () => true, () => "/sign_in?return_to=" + to.path ); }); ...
- src/shared/me.tsx
1 2 3 4 5 6 7 8 9 10
import { AxiosResponse } from "axios"; import { http } from "./HttpClient"; export let mePromise: Promise<AxiosResponse< {resources: {id: number}}, any >> | undefined; export const refreshMe = () => { mePromise = http.get<{ resources: { id: number } }>("/me"); return mePromise; }; export const fetchMe = refreshMe;
- src/views/SignInPage.tsx
1 2 3 4 5 6 7 8 9
const onSubmit = async (e: Event) => { ... if (!hasErrors(errors)) { ... localStorage.setItem("jwt", response.data.jwt); refreshMe(); router.push(route.query.return_to?.toString() || "/"); } };
2 自制前端mock系统
- 思路:基于vite开发服务器与响应拦截器,如果识别到是mock请求(请求参数中有标识),则拦截响应,并返回假的响应数据
2.1 封装mock
- 将mock封装为一个函数,接收响应体
- 如果mock成功,则返回假数据,结束响应;如果mock失败,则返回false,不会影响正常响应;
|
|
2.2 使用mock
- 以登录接口为例
|
|
- 以记账接口为例,获取全部tags
|
|
3 封装Tags hook&组件
- 先把重复的数据请求逻辑抽离成hooks
- 再把html、css抽离为组件
- 也可以直接使用hooks返回组件
3.1 完善ItemCreate组件(加载更多)
- 构造分页假数据
|
|
- 无论是onMounted还是onLoadMore,都是在请求数据,没有任何区别
|
|
- 于是可以将请求数据的逻辑封装为hooks
3.2 useTags
|
|
3.3 Tags组件
|
|
3.4 小问题
-
在切换“支出”与“收入”的Tab时,组件并没有切换
-
这是因为组件被缓存了,Vue 发现组件名称相同的组件,会更新组件属性,而不是切换
-
解决方案
- 两个Tags组件分别添加key属性加以区分,但每次切换都要重新请求数据,影响交互体验
- 通过v-show切换
1 2 3 4 5 6
// src/shared/Tabs.tsx <div> {nodeArr.map((item) => ( <div v-show={item.props?.name === props.selected}>{item}</div> ))} </div>
Author gsemir
LastMod 2022-08-30