背景
最近一直在试点用
uni-app
去做一些小需求,分享一下在项目中遇到的问题以及一些经验。ps:本项目整体为vue-cli
创建,项目目录结构会与hbuilderx
有差异。本项目开源于Github
项目目标
做一个用户线上预约,线下到店体验的简单预约商城小程序,常见于
美业
婚庆/摄影
教育/培训
亲子
等线下场景。小程序端使用uni-app
,后端API使用nestjs
+mongo
,服务端部署使用docker
。
系列连载
兵马未动,粮草先行
在试点uni-app
的时候,会有很多想法,以及一些小测试去看看框架本身是否自带我自己的需求。这样能感觉上能省去很多事情。一些场景:
- 有些请求需要带上
token
,能不能简单点统一都加上这个,然后统一处理请求结果。 wx.chooseAddress
授权成功或者失败后,给出统一的友好提示。wx.requestSubscribeMessage
首次(这里还得判断)统一引导用户点击同意按钮(可以去看看拼多多)。
以上种种需求,我都想统一有一个地方去处理,而不用每写一次都要拷贝相同的代码。
在我的项目架构中,我选择拦截,拦截上述api
执行。类似axios
拦截器,用起来就很简单。
// axios的拦截 对请求参数做处理
...interceptors.request.use(config => {
// 对请求头处理事情
config.headers...
return config
})
在uni
的文档中我没有找到这种功能的存在,但是撸了uni
源码我倒是发现了一个api
名为addInterceptor
,用来给uni
统计用的。这不就是添加拦截器的意思?自用,不对外?有兴趣的可以去撸源码。
有拦截器就简单了,就不用去uni
市场下一堆带有拦截功能的request
插件了。
拦截器的妙用
增强request
// 拦截request
uni.addInterceptor('request', {
// 请求前
invoke (arg: WechatMiniprogram.RequestOption) {
// 对请求头处理事情
arg.header = {
...arg.header,
token: 'xxx'
}
return arg
},
success () {},
fail () {},
complete () {},
// 返回值
returnValue (e) {
// 处理返回结果
return e
}
})
增强navigateTo
// 模拟场景一 各类交流群内经常看到的问题
uni.navigateTo({
url: 'pages/index/index' // 这么写 就是ts语法也不会报错 乍一看也没问题,但是肯定跳不过去的 pages前面少了一个/
})
// 增强它 如果没有 / 自己补上一个
uni.addInterceptor('navigateTo', {
invoke (obj: any) {
if (obj.url.slice(0, 1) !== '/') {
obj.url = `/${obj.url}`
}
return obj
}
})
// 模拟场景二 假设 /pages/index/index 为tabBar内的首页
uni.navigateTo({
url: '/pages/index/index' // 这里ts不会报错 但是运行是报错的 要用switchTab才行
})
// 继续增强它
let url = ''
uni.addInterceptor('navigateTo', {
invoke (obj: any) {
if (obj.url.slice(0, 1) !== '/') {
obj.url = `/${obj.url}`
}
url = obj.url
return obj
},
fail (e: any) {
// 错误是tabbar错误的 换成 switchTab继续
if (e.errMsg?.includes('tabbar')) {
uni.switchTab({
url
})
}
}
})
// redirectTo 也可以同理
// 它还能更强,可以预加载下一页的数据。分开下一篇讲:预加载数据
增强各类授权api
// 自己加要拦截的
const scope: Array<IScope> = [{
method: 'requestSubscribeMessage',
scope: 'scope.subscribeMessage'
}, {
method: 'chooseAddress',
scope: 'scope.address'
}]
for (const item of scope) {
uni.addInterceptor(item.method, {
invoke () {
// 打开引导提示
},
complete () {
// 关闭提示
}
})
}
写在最后
很多常用的api
都可以用拦截器去自定义一些自己常用的工具。一些复用性比较高的,可以单独再拎出来写。
如果你使用ts
的话,可以参考nestjs
制作公共的libs
。以下仅供参考:
新建
libs/interceptor
目录libs
目录与src
同级 目录下新建文件index.ts
和navigateInterceptor.ts
,内容可以参考上面。index.ts
内引入navigateInterceptor.ts
// tsconfig.json文件内
{
"compilerOptions": {
...
"paths": {
"@minh/interceptor": [
"libs/interceptor"
],
"@minh/interceptor/*": [
"libs/interceptor/*"
]
}
}
}
// 完成以上步骤后 项目内的其他ts引用就比较简单了
import { navigateInterceptor } from '@minh/interceptor'