# 🏅 Day 7 - 嵌套式路由、 useRouter & useRoute ## 今日學習目標 - 學習建立並使用嵌套式路由 - 學習在 Nuxt3 使用 useRouter 和 useRoute ## 前言 在 Day6 中,我們已學習了基礎路由結構,並提及了如下圖所示的結構。圖中使用的 product 資料夾就屬於嵌套式路由的觀念。透過這個資料夾結構,我們可以在 `/product` 底下進一步實作子頁面,協助我們在管理多個子頁面的同時保持清晰的路由結構 。  另外,圖中的 `/product/[id].vue` 檔案為動態路由,用於處理像 `/product/1` 或 `/product/2` 這類動態生成的路徑。動態路由會在後續的學習再進行探討,今天的目標將集中在嵌套式路由與 `useRouter` 、 `useRoute` 的實作。 ## 嵌套式路由 當頁面路由有多層級的頁面,例如一個主頁面下包含多個子頁面時,可以使用嵌套式路由在主要路由下建立多個子路由,以建立更直觀、清晰的 URL 結構。除此之外,若所有子頁面都有共用的區塊,可以在主頁面放入這些共用的元件,避免程式碼的重複。 關於在 Nuxt3 使用嵌套式路由可以閱讀 [官方文件](https://nuxt.com/docs/guide/directory-structure/pages#nested-routes) 。 ### 建立步驟 以下將繼續使用 `product` 路由為例來實作嵌套式路由,但我們會將動態路由 `[id].vue` 替換成靜態的產品內頁頁面 `productA.vue` 與 `productB.vue`,避免同學混淆,如下圖所示 :  步驟一. 在 `pages` 資料夾新增建立 `product.vue` 作為主要的產品頁面,後續步驟將作為嵌套路由的主容器。 ```html <!-- pages/product.vue --> <script setup></script> <template> <div class="container"> <h1>產品頁面</h1> </div> </template> <style scoped> .container { max-width: 1320px; margin: 0 auto; } </style> ``` 步驟二. 在 `pages` 資料夾內建立一個名為 `product` 的資料夾。這個資料夾將用來放置產品頁面的子路由,例如產品內頁和產品列表頁。 ```jsx pages/ |-- product/ | |-- product.vue |-- index.vue ``` 步驟三. 在`product` 資料夾內新增子頁面 `productA.vue` 與 `productB.vue` ,作為要在產品頁面下實作的嵌套式路由。 ```jsx pages/ |-- product/ | |-- productA.vue | |-- productB.vue | |-- product.vue |-- index.vue ``` ```jsx pages/product/productA.vue <script setup></script> <template> <h2>產品內頁 productA</h2> </template> <style scoped></style> ``` ```html <!-- pages/product/productB.vue --> <script setup></script> <template> <h2>產品內頁 productB</h2> </template> <style scoped></style> ``` 步驟四. 在 `product` 資料夾內新增子頁面 `index.vue` 作為產品主列表頁面,當進入 `/product/` 路徑時,這個頁面將作為 `/product/` 路徑的預設子頁面,顯示產品的主列表。 ```jsx pages/ |-- product/ | |-- productA.vue | |-- productB.vue | |-- index.vue | |-- product.vue |-- index.vue ``` ```html <!-- pages/product/index.vue --> <script setup></script> <template> <h2>產品主列表</h2> </template> <style scoped></style> ``` 步驟五. 最後,需要回到 `pages/product.vue` 使用 `<NuxtPage />` 來顯示嵌套式路由頁面的內容,並加入 `<NuxtLink>` 元件提供導航連結。當切換到 `/product/productA` 或 `/product/productB` 時,對應的頁面內容將被渲染到 `<NuxtPage />` 元件所在的位置。 另外在這一個頁面中有加入產品列表 `.product-category` ,這一區塊將作為所有子頁面共用的區塊,在切換到 `/product/productA` 和 `/product/productB` 都會被渲染。 ```html <!-- pages/product.vue --> <script setup></script> <template> <div class="container"> <h1>產品頁面</h1> <div class="product"> <div class="product-category"> <h2>產品列表</h2> <ul> <li> <NuxtLink to="/product/">全部產品</NuxtLink> </li> <li> <NuxtLink to="/product/productA">productA</NuxtLink> </li> <li> <NuxtLink to="/product/productB">productB</NuxtLink> </li> </ul> </div> <main class="product-list"> <NuxtPage /> <!-- 顯示 /product/ 下的頁面 --> </main> </div> </div> </template> <style lang="scss" scoped> .product { display: flex; gap: 1rem; &-category { width: 30%; outline: 1px solid #000; padding: 0 20px; ul { padding: 0; list-style: none; } } &-list { width: 70%; outline: 1px solid #000; } } </style> ``` ## 在 Nuxt3 使用路由方法與屬性 Nuxt3 將 `vue-router` 的功能整合進 Composables,其運作行為與 `vue-router` 相同。因此在 `pages/` 資料夾**的**頁面元件中可以使用 Composition API 的路由寫法 `useRouter()` 與 `useRoute()` 來使用路由。 ### useRoute `useRoute` 用於取得目前路由的詳細資訊,包括路由參數、查詢參數、路由名稱等。以上方範例的 `pages/product/productA.vue` 為例,以下使用 `useRoute` 來獲取不同的路由資訊: ```html <!-- pages/product/productA.vue --> <script setup> // Auto Imports const route = useRoute(); // 獲取路由中的查詢參數 // 例如 : 路由路徑為 /product/productA , route.query 為空物件 // 例如 : 路由路徑為 /product/productA?q=產品名稱 , route.query 為 { q:'產品名稱' } console.log(route.query); // 獲取包含路由路徑 ( path ) 、查詢參數 ( query ) 和 hash 的完整 URL console.log(route.fullPath); // 獲取路由的唯一名稱 ( name ) ,會以 pages 資料夾結構來命名,以 productA.vue 來說會是 product-productA console.log(route.name); </script> <template> <h2>產品內頁 productA</h2> </template> <style scoped></style> ``` 其他關於 `useRoute` 屬性的內容可以閱讀 [Nuxt3 文件](https://nuxt.com/docs/api/composables/use-route) 以及 [vue-router 文件](https://router.vuejs.org/api/interfaces/RouteLocationNormalizedLoadedTyped.html#Properties) ### useRouter `useRouter` 提供操作路由的方法,包括導航到不同的頁面、替換當前路由等。以上方範例的 `pages/index.vue` 為例,以下使用 `useRouter` 的方法搭配 `<button>` 按鈕的點擊來替換當前路由。 ```html <!-- pages/index.vue --> <script setup> // Auto Imports const router = useRouter(); </script> <template> <div class="container"> <h1>前台首頁</h1> <NuxtLink to="/product/">前往產品列表</NuxtLink> </div> <div class="container"> <!-- 在換頁的同時調用 history.pushState() 將 URL /product/productA 加入到瀏覽器的歷史紀錄中 --> <!-- history.pushState() : https://developer.mozilla.org/en-US/docs/Web/API/History/pushState --> <button type="button" @click="router.push('/product/productA')"> 使用 router.push() 換頁 </button> <!-- 在換頁的同時調用 history.replaceState() 將瀏覽器最後一筆的歷史紀錄修改成 /product/productB --> <!--history.replaceState() : https://developer.mozilla.org/zh-CN/docs/Web/API/History/replaceState --> <button type="button" @click="router.replace('/product/productB')"> 使用 router.replace() 換頁 </button> <!-- 在換頁的同時調用 history.go() ,根據傳入的參數在瀏覽器歷史紀錄中移動,傳入 -1 移動到前一頁, 1 則移動到下一頁 --> <button type="button" @click="router.go(1)">使用 router.go(1) 換頁</button> </div> </template> <style scoped></style> ``` 其他關於 `useRouter` 屬性的內容可以閱讀 [Nuxt3 文件](https://nuxt.com/docs/api/composables/use-router) 以及 [vue-router 文件](https://router.vuejs.org/api/interfaces/Router.html#Methods) <br> > 今日學習的[範例 Code - 資料夾: day7-nested-router-example](https://github.com/hexschool/nuxt-daily-tasks-2024) ## 題目 請 fork 這一份[模板](https://github.com/jasonlu0525/nuxt3-live-question/tree/day7-nested-router) ,將 `/pages/room.vue` 改為嵌套式路由,並實作房型列表與房型詳細頁面(不包含動態路由) - 房型列表頁面的 URL 需對應 `/room/`,在此頁面使用 ES6 Fetch 或 axios 串接 [前台房型 API](https://nuxr3.zeabur.app/swagger/#/Rooms%20-%20%E6%88%BF%E5%9E%8B) ,將資料寫入 `roomList` 變數 ,並在模板的 v-for 使用 roomList 渲染資料。 - 承上,模板的 HTML 、CSS 已有在 `/pages/room.vue` 中提供,需將其移至房型列表頁面並補上 API 串接的 JavaScript 。 - 房型詳細頁面的 URL 需對應 `/room/_id` ,在此頁顯示 “房型詳細頁面” h2 標題。 - 房型列表頁面的列表渲染之後,經點擊可以換頁至 `/room/_id` 。 > ❗需注意 : `/room/_id` 的 `/_id` 是靜態路由,非動態路由,請建立名稱為`_id.vue` 的檔案。 - 在房型詳細頁面中提供一個「回上一頁」的按鈕,點擊後可以使用 router 方法返回 `/room/` 的房型列表頁面。 - 確保房型頁面的巢狀路由內容能正確顯示。 ## 回報流程 將答案上傳至 GitHub 並複製 GitHub repo 連結貼至底下回報就算完成了喔 ! 解答位置請參考下圖(需打開程式碼的部分觀看)  <!-- 解答: https://github.com/jasonlu0525/nuxt3-live-answer/tree/day7-nested-router --> 回報區 --- | # | Discord | Github / 答案 | | --- | ----- | ----- | | 1 | Jim Lin | [GitHub](https://github.com/junhoulin/Nuxt3-hw-day7) | | 2 | 眼睛 | [GitHub](https://github.com/Thrizzacode/nuxt3-live-question/tree/day7-nested-router) | | 3 | Steven | [GitHub](https://github.com/y7516552/nuxt3-live-question/tree/day7) | | 4 | MY | [GitHub](https://github.com/ahmomoz/nuxt3-live-question/tree/day7-nested-router-hw) | | 5 | dragon | [GitHub](https://github.com/peterlife0617/2024-nuxt-training-homework01/tree/feature/day07) | | 6 | Ming | [GitHub](https://github.com/ming77712/2024-nuxt3-daily05) | | 7 | 松鼠 | [Github](https://github.com/meishinro/dailyMissionSeven) | | 8 | Rocky | [Github](https://github.com/WuRocky/day-7-useRouter-useRoute)| | 9 | LinaChen | [Github](https://github.com/Lina-SHU/nuxt3-live-question)| | 10 | Eden |[Github](https://github.com/1denx/NuxtDailyHw/tree/feature/day7-nested-router)| | 11 | Tough life | [GitHub](https://github.com/hakuei0115/Nuxt_testing) | | 12 | NeiL | [GitHub](https://github.com/Neil10241126/nuxt-demo/tree/day7-nested-router) | | 13 | Stan | [GitHub](https://github.com/haoxiang16/nuxt3-live-question/tree/day7-nested-router) | | 14 | Ariel | [GitHub](https://github.com/Ariel0508/nuxtday6/tree/nuxtday7) | | 15| 小木馬 | [GitHub](https://github.com/wern0531/Nuxt-test-day6) | | 16 | hsin yu | [GitHub](https://github.com/dogwantfly/nuxt3-daily-task-live-question/tree/day7-nested-router) | | 17 | wei_Rio | [GitHub](https://github.com/wei-1539/nuxtDaily7) | | 18 | hannahTW | [GitHub](https://github.com/hangineer/nuxt3-live-question/tree/day7-nested-router) | | 19 | runweiting | [GitHub](https://github.com/runweiting/2024-NUXT-Task/tree/day7) | | 20 | tanuki狸 | [GitHub](https://github.com/tanukili/Nuxt-2024-week01-2/tree/day7-nested-router) | | 21 | Fabio20 | [GitHub](https://github.com/fabio7621/nuxt3-live-question-d2/tree/nuxt3-live-day7) | | 22 | barry1104 | [GitHub](https://github.com/barrychen1104/nuxt3-live-question/tree/day7-nested-router) | | 23 | 小蹦 | [GitHub](https://github.com/lgk559/hex-Nuxt3/tree/day7-nested-router) | | 24 | Nielsen | [GitHub](https://github.com/asz8621/nuxt3-daily-task/tree/day7-nested-router) | | 25 | 阿塔 | [GitHub](https://github.com/QuantumParrot/2024-Hexschool-Nuxt-Camp-Daily-Task) | | 26 | Johnson | [GitHub](https://github.com/tttom3669/2024_hex_nuxt_daily/tree/day7-nested-router) | | 27 | lidelin | [GitHub](https://github.com/Lide/nuxt3-live-question/tree/day7-nested-router) | | 28 | bb | [GitHub](https://github.com/wicebing/nuxt3-live-question/tree/day7-nested-router) | <!-- 快速複製 | --- | ----- | [GitHub]() | -->
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up