Vue 導航
本指南涵蓋了使用 Ionic 和 Vue 建置的應用程式中路由的工作方式。
IonRouterOutlet
元件在底層使用了流行的 Vue Router 函式庫。透過 Ionic 和 Vue Router,您可以建立具有豐富頁面轉換的多頁應用程式。
您所知道關於使用 Vue Router 的路由的所有知識都可以在 Ionic Vue 中使用。讓我們來看看 Ionic Vue 應用程式的基本概念以及路由如何與之協同運作。
簡短說明
在閱讀本指南時,您可能會注意到大多數概念與沒有 Ionic Framework 的 Vue Router 中的概念非常相似。您的觀察是正確的!Ionic Vue 利用 Vue Router 的最佳部分,使使用 Ionic Framework 建置應用程式的轉換盡可能無縫。因此,我們建議盡可能依賴 Vue Router 功能,而不是嘗試建置自己的路由解決方案。
簡單路由
以下是一個範例路由設定,定義了指向「/home」URL 的單一路由。當您瀏覽「/home」時,路由會呈現 HomePage
元件。
router/index.ts
import { createRouter, createWebHistory } from '@ionic/vue-router';
import { RouteRecordRaw } from 'vue-router';
import HomePage from '@/views/Home.vue';
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'Home',
component: HomePage,
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
});
export default router;
在應用程式首次載入時,應用程式會呈現 HomePage
元件,因為這是此處設定的內容。
處理重新導向
如果我們想在首次載入時載入不同的路徑呢?為此,我們可以使用路由重新導向。重新導向的工作方式與典型的路由物件相同,但只包含一些不同的鍵
const routes: Array<RouteRecordRaw> = [
{
path: '/',
redirect: '/home',
},
{
path: '/home',
name: 'Home',
component: HomePage,
},
];
在我們的重新導向中,我們會尋找應用程式的索引路徑。然後,如果我們載入該路徑,我們會重新導向至 home
路由。
導覽至不同的路由
這一切都很棒,但實際上如何導覽至路由呢?為此,我們可以使用 router-link
屬性。讓我們建立一個新的路由設定
const routes: Array<RouteRecordRaw> = [
{
path: '/',
redirect: '/home',
},
{
path: '/home',
name: 'Home',
component: HomePage,
},
{
path: '/detail',
name: 'Detail',
component: DetailPage,
},
];
假設我們從 home
路由開始,並且我們想要新增一個按鈕,將我們帶到 detail
路由。我們可以使用以下 HTML 導覽至 detail
路由
<ion-button router-link="/detail">Go to detail</ion-button>
我們也可以使用路由器 API 在我們的應用程式中以程式設計方式導覽
<template>
<ion-page>
<ion-content>
<ion-button @click="() => router.push('/detail')">Go to detail</ion-button>
</ion-content>
</ion-page>
</template>
<script lang="ts">
import { IonButton, IonContent, IonPage } from '@ionic/vue';
import { defineComponent } from 'vue';
import { useRouter } from 'vue-router';
export default defineComponent({
name: 'HomePage',
components: {
IonButton,
IonContent,
IonPage,
},
setup() {
const router = useRouter();
return { router };
},
});
</script>
這兩個選項都提供了相同的導覽機制,只是適用於不同的使用案例。
使用 router-link
導覽
router-link
屬性可以設定在任何 Ionic Vue 元件上,當點擊該元件時,路由器將導覽至指定的路由。router-link
屬性接受字串值以及具名的路由,就像 Vue Router 中的 router.push
一樣。為了獲得額外的控制,也可以設定 router-direction
和 router-animation
屬性。
router-direction
屬性接受 forward
、back
或 none
的值,用於控制頁面轉換的方向。
router-animation
屬性接受 AnimationBuilder
函數,用於提供僅在點擊提供的元件時使用的自訂頁面轉換。AnimationBuilder
類型是一個函數,會傳回 Ionic Animation 執行個體。如需在 Ionic Vue 中使用動畫的詳細資訊,請參閱動畫文件。
<ion-button router-link="/page2" router-direction="back" :router-animation="myAnimation">Click Me</ion-button>
使用 useIonRouter
導覽
使用 router-link
的一個缺點是,您無法在導覽之前執行自訂程式碼。這使得在導覽之前發出網路請求等任務變得困難。您可以直接使用 Vue Router,但這樣您會失去控制頁面轉換的能力。這就是 useIonRouter
工具程式派上用場的地方。
useIonRouter
工具程式是一個函數,提供程式設計導覽的方法,同時完全控制頁面轉換。這使得在導覽之前執行自訂程式碼變得容易。
第一個範例讓我們將新頁面與自訂頁面轉換一起推送到堆疊上
import { defineComponent } from 'vue';
import { useIonRouter } from '@ionic/vue';
import { customAnimation } from '@/animations/customAnimation';
export default defineComponent({
...,
setup() {
const ionRouter = useIonRouter();
ionRouter.push('/page2', customAnimation);
}
});
useIonRouter
提供方便的 push
、replace
、back
和 forward
方法,讓使用常見導覽動作變得容易。它還提供 navigate
方法,可用於更複雜的導覽情境
import { defineComponent } from 'vue';
import { useIonRouter } from '@ionic/vue';
import { customAnimation } from '@/animations/customAnimation';
export default defineComponent({
...,
setup() {
const ionRouter = useIonRouter();
ionRouter.navigate('/page2', 'forward', 'replace', customAnimation);
}
});
上面的範例讓應用程式導覽至 /page2
,並使用向前方向的自訂動畫。此外,replace
值可確保應用程式在導覽時取代目前的歷史記錄項目。
useIonRouter
使用 Vue inject()
函數,且應僅在您的 setup()
函數內使用。
如需更多詳細資料以及類型資訊,請參閱useIonRouter 文件。
使用 router.go
導覽
Vue Router 有一個 router.go 方法,可讓開發人員在應用程式歷程記錄中向前或向後移動。讓我們看一個範例。
假設您有以下應用程式歷程記錄
/pageA
--> /pageB
--> /pageC
如果您在 /pageC
上呼叫 router.go(-2)
,您將被帶回 /pageA
。如果您隨後呼叫 router.go(2)
,您將被帶到 /pageC
。
router.go()
的一個主要特點是它期望您的應用程式歷程記錄是線性的。這表示 router.go()
不應在使用非線性路由的應用程式中使用。如需更多資訊,請參閱線性路由與非線性路由。
延遲載入路由
我們目前設定路由的方式使得它們在載入應用程式時包含在同一個初始區塊中,這並不總是理想的。相反地,我們可以設定我們的路由,以便在需要時載入元件
const routes: Array<RouteRecordRaw> = [
{
path: '/',
redirect: '/home',
},
{
path: '/home',
name: 'Home',
component: HomePage,
},
{
path: '/detail',
name: 'Detail',
component: () => import('@/views/DetailPage.vue'),
},
];
在這裡,我們的設定與先前相同,只不過這次 DetailPage
已被匯入呼叫所取代。這將導致 DetailPage
元件不再是應用程式載入時要求的區塊的一部分。
線性路由與非線性路由
線性路由
如果您建置了使用路由的 Web 應用程式,您可能之前使用過線性路由。線性路由表示您可以透過推入和彈出頁面在應用程式歷程記錄中向前或向後移動。
以下是行動應用程式中線性路由的範例
在此範例中,應用程式歷程記錄具有以下路徑
Accessibility
--> VoiceOver
--> Speech
當我們按下返回按鈕時,我們會遵循相同的路由路徑,只是順序相反。線性路由很有幫助,因為它可以實現簡單且可預測的路由行為。這也表示我們可以利用 Vue Router API,例如 router.go()。
線性路由的缺點是它不允許複雜的使用者體驗,例如索引標籤檢視。這就是非線性路由發揮作用的地方。
非線性路由
非線性路由對於許多學習使用 Ionic 建置行動應用程式的 Web 開發人員來說,可能是一個新的概念。
非線性路由表示使用者應返回的檢視不一定是螢幕上顯示的上一個檢視。
以下是非線性路由的範例
在上面的範例中,我們從 Originals
標籤頁開始。點擊卡片會將我們帶到 Originals
標籤頁中的 Ted Lasso
視圖。
從這裡,我們切換到 Search
標籤頁。然後,我們再次點擊 Originals
標籤頁,並返回到 Ted Lasso
視圖。此時,我們開始使用非線性路由。
為什麼這是非線性路由?我們之前所在的視圖是 Search
視圖。然而,在 Ted Lasso
視圖上按下返回按鈕應該會將我們帶回到根 Originals
視圖。之所以會這樣,是因為行動應用程式中的每個標籤頁都被視為自己的堆疊。 使用標籤頁 章節會更詳細地介紹這一點。
如果點擊返回按鈕只是從 Ted Lasso
視圖呼叫 router.go(-1)
,我們將被帶回到 Search
視圖,這是不正確的。
非線性路由允許線性路由無法處理的複雜使用者流程。然而,某些線性路由 API(例如 router.go()
)無法在此非線性環境中使用。這表示在使用標籤頁或巢狀出口時,不應使用 router.go()
。
我應該選擇哪一個?
我們建議在您需要新增非線性路由之前,盡可能保持您的應用程式簡單。非線性路由非常強大,但它也會為行動應用程式增加相當多的複雜性。
非線性路由最常見的兩個用途是標籤頁和巢狀 ion-router-outlet
。我們建議僅在您的應用程式符合標籤頁或巢狀路由器出口的使用案例時才使用非線性路由。
有關標籤頁的更多資訊,請參閱使用標籤頁。
有關巢狀路由器出口的更多資訊,請參閱巢狀路由。
共用 URL 與巢狀路由
設定路由時,一個常見的混淆點是在共用 URL 或巢狀路由之間做決定。本指南的這部分將解釋兩者,並協助您決定使用哪一個。
共用 URL
共用 URL 是一種路由配置,其中路由具有共同的 URL 片段。以下是共用 URL 配置的範例
const routes: Array<RouteRecordRaw> = [
{
path: '/dashboard',
component: DashboardMainPage,
},
{
path: '/dashboard/stats',
component: DashboardStatsPage,
},
];
上面的路由被視為「共用」,因為它們重複使用 URL 的 dashboard
片段。
巢狀路由
巢狀路由是一種路由配置,其中路由被列為其他路由的子路由。以下是巢狀路由配置的範例
const routes: Array<RouteRecordRaw> = [
{
path: '/dashboard/:id',
component: DashboardRouterOutlet,
children: [
{
path: '',
component: DashboardMainPage,
},
{
path: 'stats',
component: DashboardStatsPage,
},
],
},
];
上面的路由是巢狀的,因為它們位於父路由的 children
陣列中。請注意,父路由會呈現 DashboardRouterOutlet
元件。當您巢狀路由時,您需要呈現另一個 ion-router-outlet
實例。
我應該選擇哪一個?
當您想要在 URL 中保留兩個頁面之間的關係時,共用 URL 非常有用,可以在從頁面 A 過渡到頁面 B 時使用。在我們之前的範例中,/dashboard
頁面上的按鈕可以過渡到 /dashboard/stats
頁面。兩個頁面之間的關係因 a) 頁面轉換和 b) URL 而被保留。
當您想要在出口 A 中呈現內容,同時也在巢狀出口 B 內呈現子內容時,應使用巢狀路由。您會遇到的最常見使用案例是標籤頁。當您載入標籤頁 Ionic 入門應用程式時,您會看到在第一個 ion-router-outlet
中呈現的 ion-tab-bar
和 ion-tabs
元件。 ion-tabs
元件會呈現另一個 ion-router-outlet
,負責呈現每個標籤頁的內容。
在行動應用程式中,巢狀路由有意義的使用案例非常少。如果拿不定主意,請使用共用 URL 路由配置。我們強烈建議不要在標籤頁以外的環境中使用巢狀路由,因為它可能會使您的應用程式導覽變得混亂。
使用標籤頁
在使用標籤頁時,Ionic Vue 需要一種方式來知道哪個視圖屬於哪個標籤頁。 IonTabs
元件在這裡派上用場,但讓我們看看這看起來的路由設定
const routes: Array<RouteRecordRaw> = [
{
path: '/',
redirect: '/tabs/tab1',
},
{
path: '/tabs/',
component: Tabs,
children: [
{
path: '',
redirect: 'tab1',
},
{
path: 'tab1',
component: () => import('@/views/Tab1.vue'),
},
{
path: 'tab2',
component: () => import('@/views/Tab2.vue'),
},
{
path: 'tab3',
component: () => import('@/views/Tab3.vue'),
},
],
},
];
在這裡,我們的 tabs
路徑會載入 Tabs
元件。我們在 children
陣列中提供每個標籤頁作為路由物件。在此範例中,我們將路徑命名為 tabs
,但可以自訂此名稱。
讓我們先來看看我們的 Tabs
元件
<template>
<ion-page>
<ion-tabs>
<ion-router-outlet></ion-router-outlet>
<ion-tab-bar slot="bottom">
<ion-tab-button tab="tab1" href="/tabs/tab1">
<ion-icon :icon="triangle" />
<ion-label>Tab 1</ion-label>
</ion-tab-button>
<ion-tab-button tab="tab2" href="/tabs/tab2">
<ion-icon :icon="ellipse" />
<ion-label>Tab 2</ion-label>
</ion-tab-button>
<ion-tab-button tab="tab3" href="/tabs/tab3">
<ion-icon :icon="square" />
<ion-label>Tab 3</ion-label>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
</ion-page>
</template>
<script lang="ts">
import { IonTabBar, IonTabButton, IonTabs, IonLabel, IonIcon, IonPage, IonRouterOutlet } from '@ionic/vue';
import { ellipse, square, triangle } from 'ionicons/icons';
export default {
name: 'Tabs',
components: {
IonLabel,
IonTabs,
IonTabBar,
IonTabButton,
IonIcon,
IonPage,
IonRouterOutlet,
},
setup() {
return {
ellipse,
square,
triangle,
};
},
};
</script>
如果您之前使用過 Ionic Framework,您應該會覺得這很熟悉。我們建立一個 ion-tabs
元件並提供一個 ion-tab-bar
。 ion-tab-bar
提供 ion-tab-button
元件,每個元件都有一個 tab
屬性,該屬性與路由器配置中其對應的標籤頁相關聯。我們還提供一個 ion-router-outlet
,讓 ion-tabs
有一個出口來呈現不同的標籤頁視圖。
Ionic 中標籤頁的工作方式
Ionic 中的每個標籤頁都被視為個別的導覽堆疊。這表示如果您的應用程式中有三個標籤頁,則每個標籤頁都有自己的導覽堆疊。在每個堆疊中,您可以向前導覽(推入視圖)和向後導覽(彈出視圖)。
此行為需要注意,因為它與其他基於 Web 的 UI 程式庫中找到的大多數標籤頁實作不同。其他程式庫通常將標籤頁管理為單一歷史堆疊。
由於 Ionic 專注於協助開發人員建置行動應用程式,因此 Ionic 中的標籤頁旨在盡可能與原生行動標籤頁相符。因此,Ionic 的標籤頁中可能會有某些行為與您在其他 UI 程式庫中看到的標籤頁實作不同。請繼續閱讀以瞭解更多關於這些差異的資訊。
標籤頁中的子路由
在將其他路由新增至標籤頁時,您應該將它們寫為兄弟路由,並以父標籤頁作為路徑前綴。下面的範例將 /tabs/tab1/view
路由定義為 /tabs/tab1
路由的兄弟路由。由於此新路由具有 tab1
前綴,因此它將在 Tabs
元件內呈現,並且標籤頁 1 仍將在 ion-tab-bar
中選取。
const routes: Array<RouteRecordRaw> = [
{
path: '/',
redirect: '/tabs/tab1',
},
{
path: '/tabs/',
component: Tabs,
children: [
{
path: '',
redirect: 'tab1',
},
{
path: 'tab1',
component: () => import('@/views/Tab1.vue'),
},
{
path: 'tab1/view',
component: () => import('@/views/Tab1View.vue'),
},
{
path: 'tab2',
component: () => import('@/views/Tab2.vue'),
},
{
path: 'tab3',
component: () => import('@/views/Tab3.vue'),
},
],
},
];
在標籤頁之間切換
由於每個標籤頁都是自己的導覽堆疊,因此務必注意,這些導覽堆疊絕不應互動。這表示標籤頁 1 中絕不應有將使用者路由到標籤頁 2 的按鈕。換句話說,只有使用者點擊標籤列中的標籤按鈕時,才應變更標籤頁。
一個很好的實際範例是 iOS App Store 和 Google Play Store 行動應用程式。這些應用程式都提供標籤式介面,但沒有任何一個會將使用者跨標籤頁路由。例如,iOS App Store 應用程式中的「遊戲」標籤頁絕不會將使用者導向「搜尋」標籤頁,反之亦然。
讓我們看看一些使用標籤頁時常犯的錯誤。
多個標籤頁參考的設定標籤頁
一種常見的做法是建立一個「設定」視圖作為其自己的標籤頁。如果開發人員需要呈現多個巢狀設定選單,這很棒。然而,其他標籤頁絕不應嘗試路由到「設定」標籤頁。如上所述,「設定」標籤頁應該被啟用的唯一方法是使用者點擊適當的標籤按鈕。
如果您發現您的標籤頁需要參考「設定」標籤頁,我們建議使用 ion-modal
將「設定」視圖設為模式視窗。這是 iOS App Store 應用程式中找到的一種做法。使用這種方法,任何標籤頁都可以呈現模式視窗,而不會破壞每個標籤頁都是自己的堆疊的行動標籤頁模式。
下面的範例顯示了 iOS App Store 應用程式如何處理從多個標籤頁呈現「帳戶」視圖。透過在模式視窗中呈現「帳戶」視圖,應用程式可以在行動標籤頁最佳實務中運作,以跨多個標籤頁顯示相同的視圖。
在標籤頁之間重複使用視圖
另一種常見的做法是在多個標籤頁中呈現相同的視圖。開發人員通常會嘗試透過將視圖包含在單一標籤頁中,並讓其他標籤頁路由到該標籤頁來執行此操作。如上所述,這會破壞行動標籤頁模式,應避免這樣做。
相反,我們建議在每個標籤頁中都有參考相同元件的路由。這是像 Spotify 這樣的熱門應用程式中採用的做法。例如,您可以從「首頁」、「搜尋」和「你的資料庫」標籤頁存取專輯或 Podcast。當存取專輯或 Podcast 時,使用者會留在該標籤頁內。應用程式透過為每個標籤頁建立路由並在程式碼庫中共用通用元件來執行此操作。
下面的範例顯示了 Spotify 應用程式如何重複使用相同的專輯元件,以在多個標籤頁中顯示內容。請注意,每個螢幕擷取畫面都顯示相同的專輯,但來自不同的標籤頁。
首頁標籤頁 | 搜尋標籤頁 |
---|---|
![]() | ![]() |
元件
IonRouterOutlet
IonRouterOutlet
元件提供一個容器來渲染您的視圖。它類似於其他 Vue 應用程式中找到的 RouterView
元件,但 IonRouterOutlet
可以在同一個出口中渲染 DOM 中的多個頁面。當一個元件在 IonRouterOutlet
中渲染時,我們認為這是一個 Ionic Framework 的「頁面」。路由器出口容器控制頁面之間的過場動畫,以及控制頁面何時建立和銷毀。這有助於在視圖之間來回切換時保持狀態。
在範本中設定 IonRouterOutlet
時,不應在其中提供任何內容。雖然 IonRouterOutlet
可以巢狀於子元件中,但我們建議不要這樣做,因為這通常會使應用程式中的導航變得混亂。有關更多資訊,請參閱共用 URL 與巢狀路由。
IonPage
IonPage
元件會包裝 Ionic Vue 應用程式中的每個視圖,並允許頁面過場和堆疊導覽正常運作。每個使用路由器導航到的視圖都必須包含一個 IonPage
元件。
<template>
<ion-page>
<ion-header>
<ion-toolbar>
<ion-title>Home</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">Hello World</ion-content>
</ion-page>
</template>
<script lang="ts">
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/vue';
import { defineComponent } from 'vue';
export default defineComponent({
components: {
IonContent,
IonHeader,
IonPage,
IonTitle,
IonToolbar,
},
});
</script>
透過 IonModal
或 IonPopover
呈現的元件通常不需要 IonPage
元件,除非您需要一個包裝元素。在這種情況下,我們建議使用 IonPage
,以便仍然正確計算元件的尺寸。
函式
useIonRouter
▸ useIonRouter(): UseIonRouterResult
傳回 Ionic 路由器實例,其中包含用於導航、自訂頁面過場動畫以及原生功能路由內容的 API 方法。此函式可以與 Vue 的 useRouter
函式結合使用。
有關範例用法,請參閱我們的實用函式。
URL 參數
讓我們擴展一下我們原來的路由範例,以展示如何使用 URL 參數
const routes: Array<RouteRecordRaw> = [
{
path: '/',
redirect: '/home',
},
{
path: '/home',
name: 'Home',
component: HomePage,
},
{
path: '/detail/:id',
name: 'Detail',
component: DetailPage,
},
];
請注意,我們現在已在 detail
路徑字串的末尾新增了 :id
。URL 參數是我們路由路徑的動態部分。當使用者導航到例如 /details/1
的 URL 時,「1」會儲存到名為「id」的參數中,該參數可以在路由渲染時在元件中存取。
讓我們看看如何在我們的元件中使用它
<template>
<ion-page>
<ion-header>
<ion-toolbar>
<ion-title>Details</ion-title>
</ion-toolbar>
</ion-header>
<ion-content> Detail ID: {{ id }} </ion-content>
</ion-page>
</template>
<script lang="ts">
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/vue';
import { defineComponent } from 'vue';
import { useRoute } from 'vue-router';
export default defineComponent({
name: 'Detail',
components: {
IonContent,
IonHeader,
IonPage,
IonTitle,
IonToolbar,
},
setup() {
const route = useRoute();
const { id } = route.params;
return { id };
},
});
</script>
我們的 route
變數包含目前路由的實例。它也包含我們傳入的任何參數。我們可以從這裡取得 id
參數並將其顯示在螢幕上。
路由器歷史記錄
Vue Router 附帶可設定的歷史記錄模式。讓我們看看不同的選項,以及為什麼您可能想要使用每個選項。
-
createWebHistory
:此選項會建立 HTML5 歷史記錄。它利用 History API 來實現 URL 導航,而無需重新載入頁面。這是單頁應用程式最常用的歷史記錄模式。如有疑問,請使用createWebHistory
。 -
createWebHashHistory
:此選項會在您的 URL 中新增雜湊 (#
)。這對於沒有主機的 Web 應用程式或當您無法完全控制伺服器路由時很有用。搜尋引擎有時會忽略雜湊片段,因此如果 SEO 對您的應用程式很重要,您應該改為使用createWebHistory
。 -
createMemoryHistory
:此選項會建立基於記憶體的歷史記錄。這主要用於處理伺服器端渲染 (SSR)。
更多資訊
有關使用 Vue Router 在 Vue 中進行路由的更多資訊,請查看他們的文檔:http://router.vuejs.org/。