uni-app小程序客到店项目实战(二):uni拦截器(Interceptor)

10,220 阅读3分钟

背景

最近一直在试点用uni-app去做一些小需求,分享一下在项目中遇到的问题以及一些经验。ps:本项目整体为vue-cli创建,项目目录结构会与hbuilderx有差异。本项目开源于Github

项目目标

做一个用户线上预约,线下到店体验的简单预约商城小程序,常见于美业 婚庆/摄影 教育/培训 亲子等线下场景。小程序端使用uni-app,后端API使用nestjs+mongo,服务端部署使用docker

系列连载

(一):让Vant适用于uni项目

(二):uni拦截器(Interceptor)

(三):跨页面通信数据预加载

(四):是时候展示真正的艺术了

兵马未动,粮草先行

在试点uni-app的时候,会有很多想法,以及一些小测试去看看框架本身是否自带我自己的需求。这样能感觉上能省去很多事情。一些场景:

  1. 有些请求需要带上token,能不能简单点统一都加上这个,然后统一处理请求结果。
  2. wx.chooseAddress授权成功或者失败后,给出统一的友好提示。
  3. 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.tsnavigateInterceptor.ts ,内容可以参考上面。index.ts内引入navigateInterceptor.ts

// tsconfig.json文件内
{
  "compilerOptions": {
    ...
    "paths": {
      "@minh/interceptor": [
        "libs/interceptor"
      ],
      "@minh/interceptor/*": [
        "libs/interceptor/*"
      ]
    }
  }
}
// 完成以上步骤后 项目内的其他ts引用就比较简单了
import { navigateInterceptor } from '@minh/interceptor'