uni-app 页面与路由
uni-app 的路由是配置式的,所有页面必须先在 pages.json 的 pages 数组中注册,才能被访问和跳转。
这和 Nuxt 那种「文件放对位置路由就自动生成」的方式不同,多一步配置,但也更直观可控。
注册页面
新建一个页面需要做两件事,在 pages/ 下创建 .vue 文件,然后在 pages.json 中注册。
比如新建一个详情页:
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
}
},
{
"path": "pages/detail/detail",
"style": {
"navigationBarTitleText": "详情"
}
}
]
}
pages 数组中的第一个页面就是应用首页,所以想让哪个页面当首页,就把它放在数组第一位。
每个页面的 style 里还可以配置该页独有的导航条标题、背景色等,未配置的项继承 globalStyle 的全局设置。
页面跳转的两种方式
声明式导航
用 <navigator> 组件,类似 HTML 里的 <a> 标签,适合模板中固定的跳转入口:
<template>
<navigator url="/pages/detail/detail?id=1">查看商品 1</navigator>
</template>
编程式导航
用 JS API 在代码里跳转,适合点击事件、登录成功后跳转等动态场景:
<script setup>
function goDetail(id) {
uni.navigateTo({
url: `/pages/detail/detail?id=${id}`
})
}
</script>
<template>
<button @click="goDetail(1)">查看商品 1</button>
</template>
跳转 API 对比
| API | 作用 | 使用场景 |
|---|---|---|
uni.navigateTo |
跳转页面,保留当前页面,可返回 | 最常见的页面跳转 |
uni.redirectTo |
跳转页面,关闭当前页面 | 无需返回的流程,如登录页 |
uni.reLaunch |
关闭所有页面,跳转到新页面 | 回首页、切换主流程 |
uni.switchTab |
跳转到 tabBar 页面 | 切换到底部选项卡 |
uni.navigateBack |
返回上一页 | 返回按钮、取消操作 |
// 返回上一页
uni.navigateBack()
// 返回两层
uni.navigateBack({ delta: 2 })
// 跳转成功后返回首页并清空页面栈
uni.reLaunch({ url: '/pages/index/index' })
tabBar 底部选项卡
移动端 App 最常见的底部导航栏,需要在 pages.json 中配置 tabBar,同时页面必须预先注册在 pages 数组中:
{
"pages": [
{ "path": "pages/index/index" },
{ "path": "pages/list/list" },
{ "path": "pages/mine/mine" }
],
"tabBar": {
"color": "#7A7E83",
"selectedColor": "#007AFF",
"list": [
{ "pagePath": "pages/index/index", "text": "首页" },
{ "pagePath": "pages/list/list", "text": "列表" },
{ "pagePath": "pages/mine/mine", "text": "我的" }
]
}
}
配置后底部会出现三个选项卡。跳转到这些页面必须用 uni.switchTab,用 uni.navigateTo 会报错:
uni.switchTab({ url: '/pages/mine/mine' })
页面间参数传递
通过 URL 传递
跳转时把参数拼在 url 上,目标页面在 onLoad 中接收:
// 页面 A,跳转并携带参数
uni.navigateTo({
url: '/pages/detail/detail?id=1&name=phone'
})
<!-- 页面 B(detail.vue) -->
<script setup>
import { onLoad } from '@dcloudio/uni-app'
onLoad((options) => {
console.log(options.id) // '1'
console.log(options.name) // 'phone'
})
</script>
注意:onLoad 里拿到的参数都是字符串,需要数字时要自己转换,如 Number(options.id)。
要传递对象,可以先用 JSON.stringify 转成字符串,接收时再 JSON.parse 转回来:
const goods = { id: 1, price: 99 }
uni.navigateTo({
url: '/pages/detail/detail?goods=' + encodeURIComponent(JSON.stringify(goods))
})
通过事件总线传递
页面间要通信、传数据,除了 URL 还可以用 uni.$emit 和 uni.$on 事件总线,适合非跳转场景的数据通知(如登录页传登录结果给首页):
// 页面 A,发送事件
uni.$emit('login-success', { username: 'tom' })
// 页面 B,监听事件(记得在 onUnload 中移除监听)
import { onLoad, onUnload } from '@dcloudio/uni-app'
onLoad(() => {
uni.$on('login-success', (data) => {
console.log(data.username)
})
})
onUnload(() => {
uni.$off('login-success')
})
综合示例:首页 → 详情页
把上面的知识点串起来,一个完整的「首页跳详情、传参、返回」示例:
pages.json 注册两个页面(index 在前,是首页):
{
"pages": [
{ "path": "pages/index/index", "style": { "navigationBarTitleText": "首页" } },
{ "path": "pages/detail/detail", "style": { "navigationBarTitleText": "详情" } }
]
}
首页,点击商品跳转并传 id:
<script setup>
const goodsList = [
{ id: 1, name: '手机' },
{ id: 2, name: '电脑' }
]
function goDetail(id) {
uni.navigateTo({
url: `/pages/detail/detail?id=${id}`
})
}
</script>
<template>
<view class="page">
<view class="goods" v-for="item in goodsList" :key="item.id" @click="goDetail(item.id)">
<text>{{ item.name }}(点击查看详情)</text>
</view>
</view>
</template>
详情页,onLoad 接收参数:
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
const id = ref('')
onLoad((options) => {
id.value = options.id || ''
})
</script>
<template>
<view class="page">
<text>商品 ID:{{ id }}</text>
<button @click="uni.navigateBack()">返回首页</button>
</view>
</template>
运行流程是,首页点击商品 → navigateTo 打开详情页并携带 id → 详情页 onLoad 拿到参数渲染 → 点返回按钮 navigateBack 回到首页。
总结
| 知识点 | 要点 |
|---|---|
| 路由注册 | pages.json 的 pages 数组,第一个是首页 |
| 声明式跳转 | <navigator url="..."> |
| 编程式跳转 | navigateTo / redirectTo / reLaunch / switchTab / navigateBack |
| 传参 | URL query + onLoad 接收,对象用 JSON.stringify |
| tabBar | pages.json 配置,跳转用 switchTab |
一句话总结:uni-app 的路由靠 pages.json 注册,跳转用 navigateTo 加参数、onLoad 收参数、navigateBack 返回,这套流程就是 uni-app 页面交互的基本盘。