uniapp 面试题:uni-app 中如何做路由拦截和页面权限控制?

在 uni-app 面试中,“路由拦截”和“页面权限控制”是一道高频且能区分候选人项目经验深度的题目。不少开发者只停留在“用 uni.addInterceptor 拦截跳转”的层面,却忽略了页面栈、生命周期、登录态失效、白名单、tabBar 页面等实际场景。本文将从面试答题的角度,系统梳理 uni-app 中路由拦截与权限控制的完整方案。

一、先明确:uni-app 的路由机制与 Web 有何不同?

uni-app 的路由是基于页面栈管理的,而不是浏览器的 history。它提供了 navigateToredirectToreLaunchswitchTabnavigateBack 等 API。页面路径在 pages.json 中注册,分为普通页面和 tabBar 页面。

这意味着:

  • 不能像 Vue Router 那样直接使用全局前置守卫 beforeEach
  • tabBar 页面只能用 switchTab 跳转,且无法携带 query 参数。
  • 页面栈最多 10 层,navigateTo 不能跳转到 tabBar 页面。

因此,路由拦截需要借助 uni-app 提供的拦截器 API,并结合页面生命周期做兜底。

二、核心方案:uni.addInterceptor 拦截路由 API

uni-app 从 2.6.0 起支持 uni.addInterceptor,可以拦截 navigateToredirectToreLaunchswitchTabnavigateBack 等 API。

基本用法

// utils/permission.js
const whiteList = ['/pages/login/index', '/pages/index/index']

function checkLogin() {
  const token = uni.getStorageSync('token')
  return !!token
}

function isWhiteList(url) {
  const path = url.split('?')[0]
  return whiteList.includes(path)
}

const routeInterceptor = {
  invoke(args) {
    const url = args.url || ''
    if (isWhiteList(url)) return true

    if (!checkLogin()) {
      // 未登录,重定向到登录页,并记录目标页
      uni.redirectTo({
        url: `/pages/login/index?redirect=${encodeURIComponent(url)}`
      })
      return false // 返回 false 阻止本次跳转
    }
    return true
  },
  success() {},
  fail() {},
  complete() {}
}

export function setupRouteInterceptor() {
  ['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'].forEach(api => {
    uni.addInterceptor(api, routeInterceptor)
  })
}

App.vueonLaunch 中调用 setupRouteInterceptor() 即可全局生效。

关键点说明

  1. invoke 返回 false 会阻止跳转,这是拦截的核心。
  2. switchTab 也要拦截,否则用户可以直接进入 tabBar 中的“我的”等需要登录的页面。
  3. navigateBack 一般不需要拦截,但可在返回后由页面 onShow 校验权限。
  4. 白名单机制必不可少,登录页、注册页、首页等必须放行,否则会死循环。

三、登录态失效与重定向回跳

拦截时不仅要判断是否登录,还要处理“登录后回到原页面”的体验。

// 登录页 onLoad
onLoad(options) {
  this.redirect = options.redirect ? decodeURIComponent(options.redirect) : ''
},
// 登录成功后
handleLoginSuccess() {
  if (this.redirect) {
    uni.redirectTo({ url: this.redirect })
  } else {
    uni.switchTab({ url: '/pages/index/index' })
  }
}

注意:如果 redirect 指向的是 tabBar 页面,必须用 switchTab,否则会失败。可以在跳转前判断:

const tabBarPages = ['/pages/index/index', '/pages/mine/index']
const path = this.redirect.split('?')[0]
if (tabBarPages.includes(path)) {
  uni.switchTab({ url: path })
} else {
  uni.redirectTo({ url: this.redirect })
}

四、页面级权限控制:onShow + 角色判断

路由拦截只能覆盖通过 API 跳转的场景。如果用户通过物理返回键、小程序码、分享链接直接进入某个页面,拦截器可能不会触发。因此需要在页面生命周期中做二次校验。

// 需要权限的页面
onShow() {
  const token = uni.getStorageSync('token')
  const userInfo = uni.getStorageSync('userInfo')
  if (!token) {
    uni.redirectTo({ url: '/pages/login/index' })
    return
  }
  // 角色权限
  if (this.requiredRole && userInfo.role !== this.requiredRole) {
    uni.showToast({ title: '无访问权限', icon: 'none' })
    setTimeout(() => uni.navigateBack(), 1500)
  }
}

更优雅的做法是封装一个 权限 mixin自定义 hooks

// mixins/auth.js
export default {
  onShow() {
    const { auth = false, role = '' } = this.$options
    if (!auth) return
    const token = uni.getStorageSync('token')
    if (!token) {
      uni.redirectTo({ url: '/pages/login/index' })
      return
    }
    if (role) {
      const userInfo = uni.getStorageSync('userInfo') || {}
      if (userInfo.role !== role) {
        uni.showToast({ title: '无权限', icon: 'none' })
        uni.navigateBack()
      }
    }
  }
}

页面中使用:

export default {
  auth: true,
  role: 'admin',
  mixins: [authMixin]
}

五、tabBar 页面的特殊处理

tabBar 页面无法通过 navigateTo 进入,且 switchTab 不携带参数。常见需求是“未登录时点击‘我的’跳转到登录页”。

由于 tabBar 的点击事件无法直接拦截,通常有两种做法:

  1. 在 tabBar 页面的 onShow 中校验,未登录则 uni.redirectTo 到登录页。
  2. 使用自定义 tabBar(如 uni-appmidButton 或自定义组件),在点击时先判断登录态。

推荐第一种,简单可靠:

// pages/mine/index.vue
onShow() {
  if (!uni.getStorageSync('token')) {
    uni.redirectTo({ url: '/pages/login/index' })
  }
}

六、面试答题要点总结

回答这道题时,建议按以下结构展开,体现系统性:

  1. 说明差异:uni-app 没有 Vue Router 的全局守卫,需用 uni.addInterceptor
  2. 核心实现:拦截 navigateToredirectToreLaunchswitchTab,在 invoke 中判断登录态,返回 false 阻止跳转。
  3. 白名单:登录页、首页等必须放行,避免死循环。
  4. 重定向回跳:登录后回到原页面,注意 tabBar 页面用 switchTab
  5. 兜底方案:页面 onShow 中二次校验,防止物理返回、分享链接等绕过拦截。
  6. 角色权限:通过 mixin 或 hooks 统一处理,区分不同角色可访问的页面。
  7. tabBar 特殊处理:在 tabBar 页面的 onShow 中校验登录态。

如果能进一步提到 动态路由(根据权限生成 pages.json 或使用 uni-simple-router 插件)、token 过期自动刷新拦截器移除uni.removeInterceptor)等,会是不错的加分项。

七、结语

uni-app 的路由拦截与权限控制,本质是“API 拦截 + 页面生命周期兜底 + 白名单与角色管理”的组合拳。面试中不要只背 API,而要讲清楚为什么需要多层防护、如何处理边界情况。掌握这套方案,不仅能应对面试,也能直接落地到实际项目中。

未经允许不得转载:任鹏个人博客 » uniapp 面试题:uni-app 中如何做路由拦截和页面权限控制?

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏