uni-app 路由跳转与页面导航 —— 终极详解(对标 iOS / Android / 鸿蒙三端原生)

参考官方文档:


一、核心概念:uni-app 的路由到底是什么?

1.1 一句话定义

uni-app 的路由(Route) = 框架统一管理的页面注册表 + 页面栈 + 跳转规则

不是 Vue Router。uni-app 没有使用 vue-router,而是自己实现了一套类小程序 的路由系统。原因是:小程序平台(微信、支付宝等)本身就有自己的页面栈管理机制,uni-app 必须兼容所有平台,所以用 pages.json 做统一注册,用框架内置的页面栈做统一管理。

1.2 与 Vue Router 的本质区别

对比项 Vue Router(Web SPA) uni-app 路由
路由配置文件 router/index.js 中用代码配置 pages.json 中用 JSON 配置
页面切换方式 同一个 HTML 文件内切换组件(SPA) 真正切换页面(每个页面是独立的 WebView / 原生页面)
页面栈管理 浏览器 History 或 Hash 框架自维护的页面栈(最多 10 层)
路由守卫 beforeEach / beforeEnter / beforeResolve 无内置守卫,需用 uni.addInterceptor 自行拦截
动态路由 支持 :id* 通配符 不支持动态路由,所有页面必须静态注册
嵌套路由 支持 <router-view> 嵌套 不支持页面嵌套页面

二、路由注册:pages.json(一切的起点)

2.1 官方文档原文核心

uni-app 页面路由为框架统一管理,开发者需要在 pages.json 里配置每个路由页面的路径和页面样式。类似小程序在 app.json 中配置页面路由。

2.2 完整配置示例

json 复制代码
{
  "pages": [
    {
      "path": "pages/index/index",
      "style": {
        "navigationBarTitleText": "首页",
        "navigationBarBackgroundColor": "#007AFF",
        "enablePullDownRefresh": true
      }
    },
    {
      "path": "pages/detail/detail",
      "style": {
        "navigationBarTitleText": "详情"
      }
    },
    {
      "path": "pages/mine/mine",
      "style": {
        "navigationBarTitleText": "我的"
      }
    }
  ],
  "tabBar": {
    "list": [
      { "pagePath": "pages/index/index", "text": "首页", "iconPath": "static/tab-home.png", "selectedIconPath": "static/tab-home-active.png" },
      { "pagePath": "pages/mine/mine", "text": "我的", "iconPath": "static/tab-mine.png", "selectedIconPath": "static/tab-mine-active.png" }
    ]
  },
  "globalStyle": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "uni-app",
    "navigationBarBackgroundColor": "#F8F8F8",
    "backgroundColor": "#F8F8F8"
  }
}

2.3 关键规则

规则 说明
pages 数组第一项 = 应用首页 框架启动时自动加载第一个页面
path 不带文件后缀 pages/index/index,不写 .vue
所有可跳转页面必须注册 未注册的页面跳转无效,控制台报错
tabBar 页面必须同时出现在 pages 数组中 否则 tabBar 不生效
tabBar 最少 2 项,最多 5 项 平台限制

2.4 对标三端原生

uni-app iOS Android 鸿蒙 ArkTS
pages.json 注册页面 Storyboard 中拖入 ViewController 并设 Storyboard ID;或代码中 UIViewController 子类 AndroidManifest.xml 中注册 <activity android:name=".DetailActivity"> src/main/resources/base/profile/main_pages.jsonsrc 数组中注册页面路径
pages[0] = 首页 window.rootViewController = 根控制器 LAUNCHER intent-filter 的 Activity main_pages.json 中第一个路径
tabBar.list UITabBarController + 各 tab 的 UIViewController BottomNavigationView / TabLayout + Fragment Tabs 组件 + TabContent

三、页面栈模型(最核心的概念)

3.1 官方文档原文

框架以的形式管理当前所有页面,当发生路由切换的时候,页面栈的表现如下:

3.2 页面栈变化表(官方)

路由方式 页面栈表现 触发时机
初始化 新页面入栈 uni-app 打开的第一个页面
打开新页面 新页面入栈 调用 uni.navigateTo 或使用 <navigator open-type="navigate">
页面重定向 当前页面出栈,新页面入栈 调用 uni.redirectTo 或使用 <navigator open-type="redirect">
页面返回 页面不断出栈,直到目标返回页 调用 uni.navigateBack 或使用 <navigator open-type="navigateBack">
Tab 切换 当前页面出栈,新 Tab 页面入栈(非 tabBar 页面全部出栈) 调用 uni.switchTab 或使用 <navigator open-type="switchTab">
重启动 所有页面出栈,新页面入栈 调用 uni.reLaunch 或使用 <navigator open-type="reLaunch">

3.3 图示理解

scss 复制代码
【初始状态】打开 App,加载首页
┌──────────┐
│ 首页(A)  │  ← 栈底 = 栈顶(只有1个页面)
└──────────┘

【navigateTo → 详情页(B)】
┌──────────┐
│ 详情页(B)│  ← 栈顶(当前显示)
│ 首页(A)  │  ← 栈底
└──────────┘

【再 navigateTo → 评论页(C)】
┌──────────┐
│ 评论页(C)│  ← 栈顶
│ 详情页(B)│
│ 首页(A)  │  ← 栈底
└──────────┘

【navigateBack delta=1】→ 回到 B
┌──────────┐
│ 详情页(B)│  ← 栈顶
│ 首页(A)  │  ← 栈底
└──────────┘

【redirectTo → 结果页(D)】→ B 出栈,D 入栈
┌──────────┐
│ 结果页(D)│  ← 栈顶(当前显示)
│ 首页(A)  │  ← 栈底(B 被销毁了!)
└──────────┘

【reLaunch → 登录页(E)】→ 全部清空
┌──────────┐
│ 登录页(E)│  ← 唯一的页面
└──────────┘

【switchTab → 我的页】→ 关闭所有非 Tab 页
┌──────────┐
│ 我的页   │  ← 栈顶(tabBar 页面)
└──────────┘

3.4 页面栈上限

页面栈最多 10 层。 超过后 uni.navigateTo 将失效(静默失败,不跳转也不报错)。

3.5 对标三端原生

uni-app 页面栈 iOS Android 鸿蒙
栈最多 10 层 UINavigationController.viewControllers 数组,理论无上限(受内存限制) Task Stack(任务栈),默认无硬性上限(但系统可能回收) router 路由栈,官方建议不超过 32 层
getCurrentPages() 获取栈 navigationController.viewControllers ActivityManager.getRunningTasks() 或自行维护栈 router.getState() 获取当前路由信息
栈底 = 首页 viewControllers[0] = rootViewController 任务栈底部 = Launcher Activity 路由栈第一个元素

四、两种跳转方式:声明式 vs 编程式

4.1 官方文档原文

uni-app 有两种页面路由跳转方式:

  1. 使用 navigator 组件(声明式)
  2. 调用 API(编程式)

4.2 方式一:<navigator> 组件(声明式)

类似 HTML 的 <a> 标签,但只能跳转本地页面

xml 复制代码
<!-- 最基础用法 -->
<navigator url="/pages/detail/detail?id=123">去详情</navigator>

<!-- 指定跳转类型 -->
<navigator url="/pages/mine/mine" open-type="switchTab">去我的</navigator>

<!-- 返回上一页 -->
<navigator open-type="navigateBack" delta="1">返回</navigator>

<navigator> 完整属性表(官方)

属性名 类型 默认值 说明
url String --- 应用内的跳转链接,相对路径或绝对路径,不加 .vue 后缀
open-type String navigate 跳转类型(见下表)
delta Number 1 open-type="navigateBack" 时,返回的层数
animation-type String 平台默认 跳转动画类型(仅 App 端有效)
animation-duration Number 平台默认 动画时长(ms)
hover-class String navigator-hover 点击态样式类
hover-start-time Number 50 按住后多久出现点击态(ms)
hover-stay-time Number 600 手指松开后点击态保留时间(ms)

open-type 有效值

open-type 值 等价的 API 说明
navigate uni.navigateTo() 保留当前页,跳转新页面(默认值
redirect uni.redirectTo() 关闭当前页,跳转新页面
switchTab uni.switchTab() 跳转到 tabBar 页面,关闭所有非 tabBar 页面
reLaunch uni.reLaunch() 关闭所有页面,打开新页面
navigateBack uni.navigateBack() 关闭当前页面,返回上一级或多级页面
exit --- 退出小程序(仅微信小程序 2.1.0+)

对标三端原生

uni-app <navigator> iOS Android 鸿蒙
声明式跳转组件 Storyboard 中的 Segue(拖线连接两个 VC) XML 中的 <intent-filter> + startActivity;或 Jetpack Navigation 的 <action> Navigation 组件的 navDestination + router.pushUrl
open-type 切换行为 Segue 类型:push / present / replace Intent 的 Flag:FLAG_ACTIVITY_NEW_TASK / CLEAR_TASK router.pushUrl / replaceUrl / back

4.3 方式二:API 编程式跳转(重点)


五、5 个路由 API 逐一详解

5.1 uni.navigateTo(OBJECT) --- 压栈跳转(最常用)

官方定义

保留当前页面,跳转到应用内的某个页面。使用 uni.navigateBack 可以返回到原页面。

参数表

参数 类型 必填 说明
url String 需要跳转的应用内非 tabBar 页面路径,路径后可带参数,参数与路径用 ? 分隔,多个参数用 & 连接
events Object 页面间通信通道(2.8.9+ 支持)
animationType String 窗口动画类型(仅 App 端)
animationDuration Number 窗口动画时长(ms,仅 App 端)
success Function 接口调用成功的回调
fail Function 接口调用失败的回调
complete Function 接口调用结束的回调(成功或失败都执行)

代码示例

php 复制代码
// 基础跳转
uni.navigateTo({
  url: '/pages/detail/detail?id=123&name=test'
})

// 带 EventChannel 的跳转(页面间通信)
uni.navigateTo({
  url: '/pages/detail/detail',
  events: {
    // 为被打开页面注册的监听事件
    'onDataChanged': function(data) {
      console.log('子页面传回的数据:', data)
    }
  },
  success: function(res) {
    // 通过 eventChannel 向被打开页面传送数据
    res.eventChannel.emit('initData', { id: 123, title: 'Hello' })
  }
})

⚠️ 限制

  • 不能跳转到 tabBar 页面(会静默失败)
  • 页面栈最多 10 层,超出后此 API 无效

对标三端

iOS Android 鸿蒙
代码 self.navigationController?.pushViewController(detailVC, animated: true) startActivity(Intent(this, DetailActivity::class.java)) router.pushUrl({ url: 'pages/detail' })
传参 detailVC.itemId = 123(直接属性赋值) intent.putExtra("id", 123) router.pushUrl({ url: '...', params: { id: 123 } })
动画 push 默认从右向左滑入 默认从右向左(可自定义 overridePendingTransition 默认转场动画
栈行为 新 VC 压入 viewControllers 数组末尾 新 Activity 压入 Task Stack 顶部 新页面压入路由栈顶部

5.2 uni.redirectTo(OBJECT) --- 替换跳转

官方定义

关闭当前页面,跳转到应用内的某个页面。

参数表

参数 类型 必填 说明
url String 需要跳转的应用内非 tabBar 页面路径
animationType String 窗口动画类型(仅 App 端)
animationDuration Number 窗口动画时长(仅 App 端)
success/fail/complete Function 回调

代码示例

php 复制代码
// 登录成功后跳转到首页,关闭登录页(用户不能返回登录页)
uni.redirectTo({
  url: '/pages/home/home'
})

⚠️ 限制

  • 不能跳转到 tabBar 页面
  • 当前页面会被销毁 (触发 onUnload),无法返回
navigateTo redirectTo
当前页 保留在栈中 销毁(出栈)
能否返回 能(navigateBack) 不能
页面栈变化 +1 ±0(一出一进)
典型场景 列表→详情 中间过渡页→结果页

对标三端

iOS Android 鸿蒙
代码 navigationController.setViewControllers([newVC], animated: true) 或先 pop 再 push startActivity(intent); finish(); router.replaceUrl({ url: 'pages/home' })
本质 替换栈顶 VC 新 Activity 入栈 + 旧 Activity 销毁 替换路由栈顶元素
生命周期 旧 VC 触发 viewDidDisappear + dealloc 旧 Activity 触发 onPause → onStop → onDestroy 旧页面触发 onPageHide → aboutToDisappear

5.3 uni.reLaunch(OBJECT) --- 清栈重启

官方定义

关闭所有页面,打开到应用内的某个页面。

代码示例

php 复制代码
// 退出登录,回到登录页,清空所有页面栈
uni.reLaunch({
  url: '/pages/login/login'
})

⚠️ 特点

  • 所有页面全部销毁(包括 tabBar 页面)
  • 页面栈清零,只剩新打开的这一个页面
  • 可以跳转到 tabBar 页面,也可以跳转到非 tabBar 页面

对标三端

| | iOS | Android | 鸿蒙 |
|------|-----------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------|----------------------------------------------------------|-------------------------------------------------------------|
| 代码 | window.rootViewController = UINavigationController(rootViewController: loginVC) | `Intent intent = new Intent(this, LoginActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent);` | router.clear(); router.replaceUrl({ url: 'pages/login' }) |
| 本质 | 直接换掉根控制器,旧栈全部释放 | 清空整个任务栈,创建新任务 | 清空路由栈,替换为新页面 |
| 内存影响 | 所有旧 VC 被释放 | 所有旧 Activity 被 destroy | 所有旧页面组件被销毁 |


5.4 uni.switchTab(OBJECT) --- Tab 页切换

官方定义

跳转到 tabBar 页面,并关闭所有其他非 tabBar 页面。

代码示例

css 复制代码
uni.switchTab({
  url: '/pages/mine/mine'
})

⚠️ 关键限制

限制 说明
只能跳 tabBar 页面 url 必须是 tabBar.list 中声明的页面
不能传参数 url 后面拼参数无效!
关闭所有非 tabBar 页面 页面栈中非 Tab 页面全部销毁

如果需要给 Tab 页传数据怎么办?

php 复制代码
// 方案1:全局状态管理(Pinia / Vuex)
import { useStore } from '@/store'
const store = useStore()
store.selectedId = 123
uni.switchTab({ url: '/pages/mine/mine' })

// 方案2:uni.$emit 事件总线
uni.$emit('updateMineData', { id: 123 })
uni.switchTab({ url: '/pages/mine/mine' })

// 方案3:uni.setStorageSync 本地缓存
uni.setStorageSync('pendingData', { id: 123 })
uni.switchTab({ url: '/pages/mine/mine' })

对标三端

iOS Android 鸿蒙
代码 tabBarController.selectedIndex = 2tabBarController.selectedViewController = mineVC bottomNavigationView.selectedItemId = R.id.mine 或切换 Fragment 修改 Tabs 组件的 index 状态变量
本质 UITabBarController 切换当前显示的子控制器 切换 BottomNavigationView 选中项 + FragmentTransaction show/hide 切换 TabContent 显示
其他 Tab 页 不销毁,只是被隐藏(viewDidDisappear 不销毁,Fragment 被 hide 或 detach 不销毁,只是不显示

5.5 uni.navigateBack(OBJECT) --- 返回

官方定义

关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层。

参数表

参数 类型 默认值 说明
delta Number 1 返回的页面数,如果 delta 大于现有页面数,则返回到首页

代码示例

scss 复制代码
// 返回上一页
uni.navigateBack({ delta: 1 })

// 返回上3页
uni.navigateBack({ delta: 3 })

// 动态计算:返回到首页
const pages = getCurrentPages()
uni.navigateBack({ delta: pages.length - 1 })

对标三端

| | iOS | Android | 鸿蒙 |
|------|----------------------------------------------------------------------|------------------------------------------------------|----------------------------|-------------------------|
| 返回1层 | navigationController.popViewController(animated: true) | finish() 或用户按返回键 | router.back() |
| 返回多层 | navigationController.popToViewController(targetVC, animated: true) | 连续 finish() 多次;或用 Intent.FLAG_ACTIVITY_CLEAR_TOP | router.back() 多次调用 |
| 返回首页 | navigationController.popToRootViewController(animated: true) | Intent + `FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP` | 循环 router.back() 直到栈底 |


六、5 个 API 终极对比表

API 当前页处理 页面栈变化 能跳 tabBar? 能传参数? 典型场景
navigateTo 保留 叠加(+1) ❌ 不能 ✅ URL 参数 / EventChannel 列表→详情
redirectTo 关闭 替换(±0) ❌ 不能 ✅ URL 参数 中间页→结果页
reLaunch 全部关闭 清零→新建(=1) ✅ 能 ✅ URL 参数 退出登录→登录页
switchTab 关闭非Tab页 仅保留Tab页 ✅ 只能跳Tab ❌ 不能传参 切换底部Tab
navigateBack 关闭当前页 减少(-delta) --- --- 返回上一页

七、页面传参详解

7.1 URL 参数(最基础)

javascript 复制代码
// 发送方
uni.navigateTo({
  url: '/pages/detail/detail?id=123&title=' + encodeURIComponent('你好世界')
})

// 接收方(目标页面的 onLoad 中)
onLoad(options) {
  console.log(options.id)      // '123'
  console.log(decodeURIComponent(options.title))  // '你好世界'
}

对标三端

iOS Android 鸿蒙
传参方式 直接属性赋值:detailVC.itemId = 123 intent.putExtra("id", 123) router.pushUrl({ params: { id: 123 } })
取参方式 在目标 VC 中直接读属性 getIntent().getIntExtra("id", 0) router.getParams()['id']

7.2 EventChannel 页面通信(2.8.9+,推荐)

这是 uni-app 独有的机制,不需要全局状态,直接在两个页面之间建立通信管道。

javascript 复制代码
// ===== 页面A(发送方)=====
uni.navigateTo({
  url: '/pages/pageB/pageB',
  events: {
    // 监听页面B发来的事件
    'onResult': function(data) {
      console.log('B 传回的数据:', data)
    }
  },
  success: function(res) {
    // 向页面B发送数据
    res.eventChannel.emit('initData', { id: 123, list: [1,2,3] })
  }
})

// ===== 页面B(接收方)=====
onLoad() {
  const eventChannel = this.getOpenerEventChannel()
  
  // 监听页面A发来的数据
  eventChannel.on('initData', function(data) {
    console.log('A 发来的数据:', data)
  })
  
  // 向页面A发送数据
  eventChannel.emit('onResult', { status: 'success' })
}

对标三端

iOS Android 鸿蒙
类似机制 闭包回调 / delegate 协议 / NotificationCenter startActivityForResult + onActivityResult(旧)/ ActivityResultLauncher(新) routerback 配合 params 回传;或 EventHub
本质 双向通信管道 请求-响应模式 事件订阅

7.3 全局事件总线 uni.$emit / uni.$on

javascript 复制代码
// 任意页面发送
uni.$emit('dataUpdated', { id: 456 })

// 任意页面监听(通常在 onLoad 中注册,onUnload 中注销)
onLoad() {
  uni.$on('dataUpdated', this.onDataUpdated)
},
onUnload() {
  uni.$off('dataUpdated', this.onDataUpdated)
},
methods: {
  onDataUpdated(data) {
    console.log('收到更新:', data)
  }
}

八、页面生命周期与路由跳转的关系

8.1 页面生命周期一览(官方)

生命周期 触发时机 触发次数
onLoad(options) 页面加载时,可获取 URL 参数 一次
onShow() 页面显示/切入前台时 多次(每次显示都触发)
onReady() 页面初次渲染完成 一次
onHide() 页面隐藏/切入后台时 多次
onUnload() 页面卸载(销毁)时 一次

8.2 不同跳转方式触发的生命周期

跳转方式 旧页面触发 新页面触发
navigateTo onHide onLoad → onShow → onReady
navigateBack onUnload(被销毁的那个) 前一个页面触发 onShow
redirectTo onUnload onLoad → onShow → onReady
reLaunch 所有页面 onUnload onLoad → onShow → onReady
switchTab 非 Tab 页面 onUnload;当前 Tab 页 onHide 目标 Tab 页 onShow(首次还有 onLoad → onReady

8.3 对标三端原生生命周期

uni-app iOS UIViewController Android Activity 鸿蒙 ArkTS 页面
onLoad viewDidLoad onCreate aboutToAppear
onShow viewWillAppear / viewDidAppear onResume onPageShow
onReady viewDidLayoutSubviews(首次布局完成) onWindowFocusChanged(true) 页面首次渲染完成回调
onHide viewWillDisappear / viewDidDisappear onPause / onStop onPageHide
onUnload dealloc(ARC 释放时) onDestroy aboutToDisappear

九、getCurrentPages() --- 获取当前页面栈

官方定义

getCurrentPages() 函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面。

scss 复制代码
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]  // 当前页面
const prevPage = pages[pages.length - 2]     // 上一个页面

console.log(currentPage.route)  // 当前页面路由路径,如 'pages/detail/detail'

每个页面实例的属性和方法

属性/方法 说明 平台
page.route 当前页面的路由路径 全平台
page.$vm 当前页面的 Vue 实例 全平台
page.$getAppWebview() 获取当前页面的 webview 对象实例 仅 App

⚠️ 注意

请勿修改页面栈,以免造成页面状态错误。


十、App 端特有的窗口动画(animationType

uni.navigateTouni.redirectToApp 端支持自定义窗口动画:

animationType 值 说明
slide-in-right 从右侧滑入(默认
slide-in-left 从左侧滑入
slide-in-top 从上侧滑入
slide-in-bottom 从下侧滑入
fade-in 淡入
zoom-out 缩放淡入
pop-in 从底部弹出
none 无动画
php 复制代码
uni.navigateTo({
  url: '/pages/detail/detail',
  animationType: 'slide-in-bottom',
  animationDuration: 300
})

对标三端

iOS Android 鸿蒙
自定义转场动画 UIViewControllerTransitioningDelegate + 自定义 UIViewControllerAnimatedTransitioning overridePendingTransition(enterAnim, exitAnim)ActivityOptions.makeCustomAnimation() pageTransition 中自定义 PageTransitionEnter / PageTransitionExit

十一、路由守卫(uni-app 没有内置,需自行实现)

uni-app 没有 Vue Router 的 beforeEach 全局守卫。但可以用 uni.addInterceptor 拦截所有路由 API:

javascript 复制代码
// 在 App.vue 的 onLaunch 或 main.js 中
const interceptors = ['navigateTo', 'redirectTo', 'reLaunch', 'switchTab']

interceptors.forEach(method => {
  uni.addInterceptor(method, {
    invoke(args) {
      // 跳转前拦截
      const needLogin = ['/pages/order/order', '/pages/mine/mine']
      const token = uni.getStorageSync('token')
      
      if (needLogin.some(p => args.url.startsWith(p)) && !token) {
        uni.showToast({ title: '请先登录', icon: 'none' })
        uni.navigateTo({ url: '/pages/login/login' })
        return false  // 返回 false 阻止本次跳转
      }
    }
  })
})

对标三端

iOS Android 鸿蒙
路由守卫 pushViewController 前手动判断;或自定义 Router 类 startActivity 前判断;或用 ActivityResultContracts 拦截 router.pushUrl 前判断
框架级方案 无内置(通常自封装 Router) Jetpack Navigation 的 NavigationUI + NavigationGuard(非官方) 无内置

十二、完整技术栈对照总表

功能维度 uni-app iOS 原生 Android 原生 鸿蒙 ArkTS
路由注册 pages.json Storyboard / 代码注册 VC AndroidManifest.xml 注册 Activity main_pages.json
页面容器 框架页面栈(WebView / nvue) UINavigationController Task Stack(Activity 栈) router 路由栈
压栈跳转 uni.navigateTo pushViewController:animated: startActivity(intent) router.pushUrl()
替换跳转 uni.redirectTo 替换 viewControllers 栈顶 startActivity + finish() router.replaceUrl()
清栈重启 uni.reLaunch rootViewController CLEAR_TASK + NEW_TASK router.clear() + replaceUrl()
Tab 切换 uni.switchTab UITabBarController.selectedIndex BottomNavigationView / TabLayout Tabs 组件 index
返回 uni.navigateBack popViewController / popToRootViewController finish() / onBackPressed() router.back()
获取栈 getCurrentPages() navigationController.viewControllers ActivityManager / 自维护 router.getState()
声明式跳转 <navigator> 组件 Storyboard Segue Jetpack Navigation <action> Navigation + navPathStack
传参 URL 参数 / EventChannel 属性赋值 / delegate Intent.putExtra / Bundle router.pushUrl({ params })
双向通信 EventChannel delegate / closure / NotificationCenter startActivityForResult / ActivityResultLauncher EventHub / emitter
全局事件 uni.$emit / uni.$on NotificationCenter LocalBroadcastManager / EventBus commonEventManager / emitter
路由守卫 uni.addInterceptor(自行封装) 手动判断 / 自封装 Router 手动判断 / 拦截器模式 手动判断
转场动画 animationType 参数(App 端) UIViewControllerTransitioningDelegate overridePendingTransition / ActivityOptions pageTransition
页面生命周期 onLoad/onShow/onReady/onHide/onUnload viewDidLoad/viewWillAppear/viewDidAppear/viewWillDisappear/dealloc onCreate/onResume/onPause/onStop/onDestroy aboutToAppear/onPageShow/onPageHide/aboutToDisappear
页面栈上限 10 层 无硬性限制(受内存) 无硬性限制(受系统回收) 建议 ≤ 32 层
Vue Router 兼容 不兼容(可在插件市场找 vue-router 适配插件) --- --- ---

十三、常见踩坑与最佳实践

13.1 必须避免的坑

原因 解决方案
navigateTo 跳 tabBar 页无反应 API 设计限制 改用 switchTab
switchTab 传参拿不到 API 设计限制 用 Pinia / uni.$emit / Storage
页面栈超 10 层后跳转失效 栈满 关键节点用 redirectTo 替换;或用 reLaunch 重置
onLoad 在 Tab 页只执行一次 Tab 页不会重新创建 需要每次刷新就写在 onShow
redirectTo 后无法返回 当前页已被销毁 这是设计意图,确认业务需要再使用
URL 参数含中文或特殊字符 未编码 使用 encodeURIComponent() 编码

13.2 最佳实践总结

markdown 复制代码
选择跳转方式的决策树:

目标页面是 tabBar 页面?
├── 是 → uni.switchTab
└── 否 → 需要保留当前页面(能返回)?
    ├── 是 → 页面栈是否已满(≥10)?
    │   ├── 是 → uni.redirectTo(替换,防止溢出)
    │   └── 否 → uni.navigateTo(最常用)
    └── 否 → 是否需要关闭所有页面?
        ├── 是 → uni.reLaunch
        └── 否 → uni.redirectTo

十四、参考文档链接汇总

文档 链接
页面与路由跳转 uniapp.dcloud.net.cn/tutorial/pa...
路由 API(5 个方法) uniapp.dcloud.net.cn/api/router....
navigator 组件 uniapp.dcloud.net.cn/component/n...
pages.json 配置 uniapp.dcloud.net.cn/collocation...
getCurrentPages uniapp.dcloud.net.cn/api/window/...
页面生命周期 uniapp.dcloud.net.cn/tutorial/pa...

以上就是基于 uni-app 官方文档的完整梳理,覆盖了路由注册、页面栈模型、5 个 API 的参数/行为/限制、navigator 组件、传参方式、EventChannel 通信、生命周期联动、路由守卫、窗口动画等全部技术点,并逐一对标了 iOS(UINavigationController / UITabBarController)、Android(Activity Task Stack / Intent)、鸿蒙(router / Navigation)三端原生实现。如果某个部分需要更深入的代码级展开,随时告诉我。

相关推荐
Heo1 小时前
大厂前端调试不能只会debugger
前端·javascript·面试
用户2181697049301 小时前
Flutter (十七) 网络请求
前端
cidy_981 小时前
React 19 + Vite 企业级前端项目:从零搭建到规范交付
前端
用户921080262862 小时前
如何把一张图片做成自定义复杂 UI 图标
前端
用户938515635072 小时前
从 0 拆解一个 Next.js 笔记系统:npx、App Router、RSC 与组件规划全记录
前端·后端·全栈
hello93072 小时前
plop代码生成器
前端
windliang2 小时前
Claude Code 源码分析(十二):错误处理与自动恢复:让 Agent 稳定运行
前端·javascript·面试
fatcoder2 小时前
玩转Docker 06 — 容器网络
前端·后端·docker
打呵欠的猫2 小时前
我用 AI 重写了项目的请求层,从 800 行"面条代码"变成 3 层洋葱模型
前端·ai编程