【拿来就用】Uniapp路由守卫终极方案:1个文件搞定全站权限控制,老板看了都点赞!

1. 前言:从 Vue-Router 到 Uniapp

在 Vue 项目中,我们使用 Vue-Router 的 beforeEach 导航守卫轻松实现路由拦截、权限校验等功能:

php 复制代码
import { createRouter, createWebHashHistory } from 'vue-router'
​
const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    { path: '/', redirect: '/login' }
  ]
})
​
// Vue-Router 导航守卫
router.beforeEach((to, from, next) => {
  if (to.path === '/login') return next()
  
  const token = sessionStorage.getItem('token')
  if (!token) {
    return next('/login')
  }
  
  next()
})

但 Uniapp 的情况不同 :作为一个跨端框架,Uniapp 没有内置类似 Vue-Router 的路由守卫机制。不过别担心,我们可以通过 Uniapp 的拦截器 API 实现相同的功能!

2. Uniapp 路由拦截器:核心概念

2.1 什么是拦截器?

Uniapp 提供了 uni.addInterceptor API,允许我们拦截特定的 API 调用。官方文档:拦截器

2.2 需要拦截哪些 API?

要实现路由守卫,我们需要拦截以下四个页面跳转 API:

  • uni.navigateTo // 保留当前页面,跳转到新页面

  • uni.redirectTo // 关闭当前页面,跳转到新页面

  • uni.reLaunch // 关闭所有页面,打开新页面

  • uni.switchTab // 跳转到 TabBar 页面

2.3 拦截器的核心:invoke 方法

每个拦截器都需要实现 invoke 方法,它会在对应的 API 调用时触发,让我们有机会在跳转前进行校验。

3. 实战:创建路由守卫工具类

utils 目录下创建 route-guard.js

javascript 复制代码
/**
 * 名称:全局路由守卫工具类
 * 功能:实现页面跳转的权限校验(类似 Vue-Router 的 beforeEach)
 * 使用:在 App.vue 的 onLaunch 中调用 initRouteGuard()
 */
​
// ==================== 配置部分 ====================
const routeConfig = {
  // 白名单:无需登录即可访问的页面路径
  whiteList: new Set([
    '/pages/login/login',
    '/pages/register/register',
    '/pages/index/index',
    '/pages/public/public-page'
  ]),
  
  // 登录页路径
  loginPage: '/pages/login/login',
  
  // Token 存储的 key
  tokenKey: 'token'
};
​
// ==================== 核心校验逻辑 ====================
/**
 * 检查路由权限
 * @param {string} url - 要跳转的页面路径
 * @returns {boolean} - 是否允许跳转
 */
const checkRoutePermission = (url) => {
  // 提取路径(去除查询参数)
  const path = url.split('?')[0];
  
  // 放行白名单
  if (routeConfig.whiteList.has(path)) {
    return true;
  }
  
  // 检查 Token
  const token = uni.getStorageSync(routeConfig.tokenKey);
  
  // 双重验证:存在且有效(这里可以添加更多验证逻辑)
  if (token && typeof token === 'string' && token.length > 0) {
    // 可以在这里添加 Token 过期验证
    // const isExpired = checkTokenExpiry(token);
    // return !isExpired;
    return true;
  }
  
  return false;
};
​
// ==================== 拦截器配置 ====================
const routeInterceptor = {
  /**
   * 拦截器核心方法
   * @param {Object} args - 原始 API 参数
   * @returns {boolean} - 是否继续执行原始 API
   */
  invoke(args) {
    console.log(`🚦 路由拦截: ${args.url}`);
    
    // 检查权限
    if (checkRoutePermission(args.url)) {
      return true; // 放行,继续执行原始跳转
    }
    
    // 无权限:跳转到登录页
    console.warn('❌ 无访问权限,跳转到登录页');
    
    // 携带 redirect 参数,登录后可以跳回原页面
    const redirectUrl = encodeURIComponent(args.url);
    
    uni.redirectTo({
      url: `${routeConfig.loginPage}?redirect=${redirectUrl}`,
      fail: (error) => {
        console.error('跳转登录页失败:', error);
      }
    });
    
    return false; // 阻止原始跳转
  }
};
​
// ==================== 初始化方法 ====================
/**
 * 初始化路由守卫
 */
export const initRouteGuard = () => {
  try {
    // 拦截所有页面跳转 API
    uni.addInterceptor('navigateTo', routeInterceptor);
    uni.addInterceptor('redirectTo', routeInterceptor);
    uni.addInterceptor('reLaunch', routeInterceptor);
    uni.addInterceptor('switchTab', routeInterceptor);
    
    console.log('✅ 路由守卫已启用');
  } catch (error) {
    console.error('❌ 路由守卫初始化失败:', error);
  }
};
​
/**
 * 移除路由守卫(特殊场景使用)
 */
export const removeRouteGuard = () => {
  try {
    uni.removeInterceptor('navigateTo');
    uni.removeInterceptor('redirectTo');
    uni.removeInterceptor('reLaunch');
    uni.removeInterceptor('switchTab');
    
    console.log('✅ 路由守卫已移除');
  } catch (error) {
    console.error('❌ 移除路由守卫失败:', error);
  }
};
​
// ==================== 辅助方法 ====================
/**
 * 更新白名单(动态配置)
 * @param {Array} newRoutes - 新的白名单路由数组
 */
export const updateWhiteList = (newRoutes) => {
  routeConfig.whiteList = new Set(newRoutes);
};
​
/**
 * 检查当前页面是否在白名单
 * @param {string} path - 页面路径
 * @returns {boolean}
 */
export const isInWhiteList = (path) => {
  return routeConfig.whiteList.has(path);
};

4. 使用指南

4.1 基础使用

App.vue 中初始化:

xml 复制代码
<script>
import { initRouteGuard } from '@/utils/route-guard.js';
​
export default {
  onLaunch() {
    console.log('App Launch');
    
    // 初始化路由守卫(必须在页面跳转前调用)
    initRouteGuard();
    
    // 其他初始化代码...
  },
  
  onShow() {
    console.log('App Show');
  },
  
  onHide() {
    console.log('App Hide');
  }
}
</script>
​
<style>
/* 全局样式 */
</style>

4.2 高级配置

ini 复制代码
// 在需要的地方动态更新配置
import { updateWhiteList, isInWhiteList } from '@/utils/route-guard.js';
​
// 添加新的白名单路由
const additionalRoutes = [
  '/pages/public/another-public',
  '/pages/guest/guest-page'
];
updateWhiteList([...routeConfig.whiteList, ...additionalRoutes]);
​
// 检查当前页面权限
const currentPage = '/pages/user/profile';
if (!isInWhiteList(currentPage)) {
  console.log('需要登录才能访问');
}

5. 实战场景扩展

场景1:不同用户角色的权限控制

kotlin 复制代码
// 扩展 checkRoutePermission 函数
const checkRoutePermission = (url, userRole) => {
  const path = url.split('?')[0];
  
  // 公开页面
  if (routeConfig.whiteList.has(path)) {
    return true;
  }
  
  // 需要登录的页面
  const token = uni.getStorageSync('token');
  if (!token) return false;
  
  // 根据角色检查权限
  const role = uni.getStorageSync('userRole') || 'user';
  
  // 管理员专属页面
  if (path.startsWith('/pages/admin/') && role !== 'admin') {
    return false;
  }
  
  // VIP 专属页面
  if (path.startsWith('/pages/vip/') && role !== 'vip') {
    return false;
  }
  
  return true;
};

场景2:Token 自动刷新

ini 复制代码
const checkRoutePermission = async (url) => {
  const path = url.split('?')[0];
  
  if (routeConfig.whiteList.has(path)) {
    return true;
  }
  
  let token = uni.getStorageSync('token');
  const tokenExpiry = uni.getStorageSync('tokenExpiry');
  
  // 检查 Token 是否过期
  if (token && tokenExpiry && Date.now() > tokenExpiry) {
    // 自动刷新 Token
    const refreshed = await refreshToken();
    if (!refreshed) {
      return false;
    }
    token = uni.getStorageSync('token');
  }
  
  return !!token;
};

场景3:路由跳转前的统一处理

javascript 复制代码
const routeInterceptor = {
  invoke(args) {
    // 统一添加时间戳参数(解决页面缓存问题)
    if (!args.url.includes('timestamp')) {
      args.url += `${args.url.includes('?') ? '&' : '?'}_t=${Date.now()}`;
    }
    
    // 页面访问统计
    logPageAccess(args.url);
    
    // 权限检查
    if (checkRoutePermission(args.url)) {
      return true;
    }
    
    // 无权限处理
    return handleNoPermission(args.url);
  }
};

6. 常见问题与解决方案

Q1: TabBar 页面拦截无效?

A : switchTab 跳转时,如果目标页面已在 TabBar 中显示,拦截可能不会触发。建议在页面的 onShow 生命周期中做二次验证。

javascript 复制代码
// 在页面中
export default {
  onShow() {
    const token = uni.getStorageSync('token');
    if (!token && !isInWhiteList(this.$page.route)) {
      uni.redirectTo({
        url: '/pages/login/login'
      });
    }
  }
}

Q2: 拦截器影响性能?

A: 拦截器的性能开销很小。如果担心性能,可以:

  1. 只在开发环境启用详细日志

  2. 对频繁访问的白名单页面做缓存

  3. 避免在拦截器中执行复杂操作

Q3: 如何调试?

javascript 复制代码
// 在 route-guard.js 中添加调试模式
const DEBUG = process.env.NODE_ENV === 'development';

const routeInterceptor = {
  invoke(args) {
    if (DEBUG) {
      console.group('🔍 路由拦截详情');
      console.log('目标URL:', args.url);
      console.log('完整参数:', args);
      console.groupEnd();
    }
    
    // ... 原有逻辑
  }
};

7. 完整示例项目结构

bash 复制代码
项目根目录/
├── pages/
│   ├── login/
│   │   └── login.vue
│   ├── home/
│   │   └── home.vue
│   └── user/
│       └── profile.vue
├── utils/
│   ├── route-guard.js    # 路由守卫工具
│   ├── auth.js          # 认证相关工具
│   └── request.js       # 请求拦截器
├── App.vue              # 初始化路由守卫
└── main.js              # 应用入口

总结

通过 Uniapp 的拦截器机制,我们成功实现了类似 Vue-Router 的路由守卫功能。关键点:

  1. 拦截四个路由 APInavigateToredirectToreLaunchswitchTab

  2. 灵活的白名单配置:支持动态更新

  3. 完善的错误处理:跳转失败时有降级方案

  4. 可扩展性强:支持角色权限、Token刷新等高级功能

这套方案已经过多个项目的验证,可以直接复制使用。根据实际需求,调整白名单和权限校验逻辑即可。

立即使用 :将上面的 route-guard.js 复制到你的项目中,然后在 App.vueonLaunch 中调用 initRouteGuard(),你的 Uniapp 应用就拥有了强大的路由守卫功能!

相关推荐
嘿siri2 小时前
uniapp enter回车键不触发消息发送,已解决
前端·前端框架·uni-app·vue
CodeCraft Studio2 小时前
Excel处理控件Aspose.Cells教程:使用C#在Excel中创建树状图
前端·c#·excel·aspose·c# excel库·excel树状图·excel sdk
咬人喵喵2 小时前
CSS Flexbox:拥有魔法的排版盒子
前端·css
LYFlied2 小时前
TS-Loader 源码解析与自定义 Webpack Loader 开发指南
前端·webpack·node.js·编译·打包
yzp01122 小时前
css收集
前端·css
暴富的Tdy2 小时前
【Webpack 的核心应用场景】
前端·webpack·node.js
遇见很ok2 小时前
Web Worker
前端·javascript·vue.js
elangyipi1232 小时前
JavaScript 高级错误处理与 Chrome 调试艺术
开发语言·javascript·chrome
风舞红枫2 小时前
前端可配置权限规则案例
前端