Router — 页面路由
基于 Native WebView 栈的页面路由,每次导航都会创建/销毁独立的 WebView 实例。
交互示例
导航 API 演示
<script setup lang="ts">
import { ref } from 'vue'
import woo from 'mini-sdk'
const url = ref('pages/detail/index')
const params = ref('id=42&type=article')
const log = ref<string[]>([])
function addLog(msg: string) {
log.value.unshift(`[${new Date().toLocaleTimeString()}] ${msg}`)
if (log.value.length > 6) log.value.pop()
}
async function doNavigateTo() {
const query = Object.fromEntries(new URLSearchParams(params.value))
await woo.navigateTo({ url: url.value, params: query })
addLog(`navigateTo("${url.value}", ${JSON.stringify(query)})`)
}
async function doNavigateBack() {
await woo.navigateBack()
addLog('navigateBack()')
}
async function doReLaunch() {
await woo.reLaunch(url.value)
addLog(`reLaunch("${url.value}")`)
}
async function doGetRoute() {
const route = woo.getRoute()
addLog(`getRoute() → path="${route.path}" query=${JSON.stringify(route.query)}`)
}
async function doGetPages() {
const res = await woo.getCurrentPages()
addLog(`getCurrentPages() → ${JSON.stringify(res.pages)}`)
}
</script>
<template>
<div class="demo-router">
<div class="form-grid">
<div class="field flex-2">
<label>目标页面路径</label>
<input v-model="url" placeholder="pages/detail/index" />
</div>
<div class="field flex-2">
<label>参数 (query string 格式)</label>
<input v-model="params" placeholder="id=42&type=article" />
</div>
</div>
<div class="btn-row">
<button class="btn btn-primary" @click="doNavigateTo">navigateTo</button>
<button class="btn btn-outline" @click="doNavigateBack">navigateBack</button>
<button class="btn btn-outline" @click="doReLaunch">reLaunch</button>
<button class="btn btn-ghost" @click="doGetRoute">getRoute</button>
<button class="btn btn-ghost" @click="doGetPages">getCurrentPages</button>
</div>
<div v-if="log.length" class="log-box">
<div v-for="(entry, i) in log" :key="i" class="log-entry">{{ entry }}</div>
</div>
</div>
</template>
<style scoped>
.demo-router { display: flex; flex-direction: column; gap: 14px; width: 100%; }
.form-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; }
.flex-2 { grid-column: span 2; }
.field { display: flex; flex-direction: column; gap: 5px; }
label { font-size: 11.5px; font-weight: 600; color: var(--vp-c-text-3); text-transform: uppercase; letter-spacing: 0.05em; }
input { padding: 7px 10px; border-radius: 6px; border: 1px solid var(--vp-c-divider); background: var(--vp-c-bg); font-size: 13px; color: var(--vp-c-text-1); font-family: var(--vp-font-family-mono); outline: none; transition: border-color 0.15s; }
input:focus { border-color: #6366f1; }
.btn-row { display: flex; gap: 8px; flex-wrap: wrap; }
.btn { padding: 7px 14px; border-radius: 6px; border: none; font-size: 13px; font-weight: 500; cursor: pointer; font-family: inherit; transition: all 0.15s; }
.btn-primary { background: #6366f1; color: white; }
.btn-primary:hover { background: #4f46e5; }
.btn-outline { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); color: var(--vp-c-text-1); }
.btn-outline:hover { background: var(--vp-c-bg-soft); }
.btn-ghost { background: transparent; color: var(--vp-c-text-2); border: 1px dashed var(--vp-c-divider); }
.btn-ghost:hover { background: var(--vp-c-bg-soft); color: var(--vp-c-text-1); }
.log-box { border: 1px solid var(--vp-c-divider); border-radius: 8px; overflow: hidden; max-height: 180px; overflow-y: auto; }
.log-entry { padding: 7px 12px; font-size: 12px; color: var(--vp-c-text-2); font-family: var(--vp-font-family-mono); border-bottom: 1px solid var(--vp-c-divider); white-space: nowrap; }
.log-entry:last-child { border-bottom: none; }
</style>
API 参考
woo.navigateTo(options)
导航到新页面(压栈),支持字符串简写。ts
// ✨ 字符串简写
await woo.navigateTo('pages/detail/index')
// 带参数
await woo.navigateTo({
url: 'pages/detail/index',
params: { id: 42, type: 'article' },
})
// 带返回值回调
woo.navigateTo({
url: 'pages/select/index',
onBack(data) {
console.log('用户选择了:', data)
},
})Options
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
url | string | ✅ | 页面路径(不含前导 /) |
params | Record<string, string | number | boolean> | ❌ | URL 查询参数 |
onBack | (data?: any) => void | ❌ | 目标页 navigateBack 时回调 |
多 WebView 注意
onBack 注册在当前 WebView 的 JS 上下文中。子页面返回时,Native 将 backResult 事件投递到本 WebView,回调自动触发。当前 WebView 在后台保活,不会丢失。
woo.navigateBack(options?)
返回上一页(弹栈),可携带数据传给上一页的 onBack。ts
// 简单返回
await woo.navigateBack()
// 跨多级返回
await woo.navigateBack({ delta: 2 })
// 携带数据返回
await woo.navigateBack({
data: { selected: 'item_1', timestamp: Date.now() },
})Options
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
delta | number | 1 | 返回层数 |
data | any | — | 传给上一页 onBack 的任意数据 |
调用后不再执行
navigateBack 后当前 WebView 即被销毁,后续代码不会执行,无需手动 return。
woo.reLaunch(options)
关闭所有页面,重新打开指定页面。支持字符串简写。ts
await woo.reLaunch('pages/home/index')
await woo.reLaunch({ url: 'pages/home/index', params: { refresh: true } })woo.navigateToTab(options)
切换到 Tab 页面,同时关闭所有非 Tab 页面。ts
await woo.navigateToTab('pages/home/index')woo.reLaunchTab(options)
重启指定 Tab(清空历史后重新加载)。常用于登出场景。ts
await woo.reLaunchTab('pages/home/index')woo.getCurrentPages()
获取当前页面栈(异步)。ts
const pages = await woo.getCurrentPages()
console.log(pages) // ['pages/home/index', 'pages/detail/index']woo.getRoute()
同步获取当前 WebView 的页面路径和 query(从 URL 解析,无 bridge)。ts
const { path, query } = woo.getRoute()
console.log(path) // 'pages/detail/index'
console.log(query) // { id: '42', type: 'article' }(均为字符串)| 运行环境 | URL 格式 | 示例 |
|---|---|---|
| 模拟器(hash 路由) | hash | http://localhost/#/pages/detail?id=1 |
| Native(pathname 路由) | pathname + search | https://host/pages/detail?id=1 |
woo.navigateToMiniApp(options)
跳转到另一个小程序。ts
await woo.navigateToMiniApp({
appId: 'com.example.partner',
path: 'pages/detail/index',
extraData: { itemId: 99 },
})