###### tags: `Vue` # Vue Router # 0. 大綱 Vue 與以前寫的 jquery 的架構大相逕庭,jquery 所建立出來的網頁屬於多頁式網頁(MPA),而Vue所建立出來的網頁為單頁式網頁(SPA),簡單說就是進入其他網頁而網址會變動但並無跳轉的跡象,~~讓使用者產生出網頁很流暢的錯覺~~。要如何達成這個魔法,就是使用到本篇所提到的Vue-Router。 # 1. 安裝 ## 1.1. 在建立專案安裝 ### 1.1.1 透過Vue UI建立專案時 ![](https://i.imgur.com/18kpoF6.png) ![](https://i.imgur.com/5eGgHnt.png) 1. 在建立專案,選擇專案模板時,選擇”手動”,按下一步。 2. 選取Router選項即可。 3. 建立成功,即可在該專案的/src找到系統自動建立的/router/index.js。 ![](https://i.imgur.com/N0QGTHl.png) ### 1.1.2 透過指令建立專案時 ![](https://i.imgur.com/7IwqrDe.png) ![](https://i.imgur.com/1OrZ7Ya.png) 1. 輸入指令建立專案後,選擇第3個選項。 2. 選擇選項”Router”。 3. 之後的部分就依個人需求自訂, 4. 建立成功,即可在該專案的/src找到系統自動建立的/router/index.js。 ## 1.2. 在專案建立後加裝 ### 1.2.1 透過Vue UI加入 ![](https://i.imgur.com/tp5Eyjx.png) 1. 按下最左邊的第2個”插件”。 2. 找到右上角的按鈕”新增vue-router”並按下,並按下"繼續" 3. 待安裝完,即可在該專案的/src找到系統自動建立的/router/index.js。 ### 1.2.2 透過指令加裝 ![](https://i.imgur.com/vFMAQDl.png) 1. 進入該專案,輸入指令: >💡 `npm install vue-router -save` 2. 在該專案下的/src中建立一個新資料夾,命名為”router”,並在其中建立”index.js”。 ![](https://i.imgur.com/qOTyPJk.png) 3. 編輯/router/index.js,內容為: ```jsx import { createRouter, createWebHashHistory } from 'vue-router' import Home from '../components/HelloWorld.vue' const About = { template: '<div>About</div>'} const routes = [ { path: '/', name: 'home', component: Home }, { path: '/about', name: 'about', component: About } ] const router = createRouter({ history: createWebHashHistory(), routes }) export default router ``` 4. 編輯最外層的main.js,將router加入。 ```jsx import { createApp } from 'vue' import App from './App.vue' import router from './router'; //新增這行 //createApp(App).mount('#app') //將這行註解或刪除 const app = createApp(App); //新增這行 app.use(router) //新增這行,將router引進 app.mount('#app') //新增這行 ``` 5. 編輯app.vue: ```html <template> <router-link to="/">Home</router-link> <!--新增這行--> <router-link to="/about">About</router-link> <!--新增這行--> <router-view></router-view> <!--新增這行--> <!--<img alt="Vue logo" src="./assets/logo.png"> 刪除或註解這行--> <!--<HelloWorld msg="Welcome to Your Vue.js App"/> 刪除或註解這行--> </template> <script> import HelloWorld from './components/HelloWorld.vue' //刪除或註解這行 export default { name: 'App', components: { HelloWorld //刪除或註解這行 } } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style> ``` 6. 啟動後,看到此畫面即成功。 ![](https://i.imgur.com/ek2mTCW.png) # 2. 介紹功能 ## 2.1 建立Router ```jsx const router = createRouter({ history: createWebHashHistory(), routes }) ``` - 使用`createRouter(options)`來建立Router - 主要常用的options有: - history : - `createWebHashHistory()` - `createWebHistory()` - routes : Router的初始路由列表,細節留至下一小節詳細說明。 ## 2.2 routes - routes為初始的路由列表,之後若要再新增其他路由可有其他指令(ex: `addRoute`)辦到。 ```jsx const routes = [ { path: '/', name: 'home', component: Home }, { path: '/about', name: 'about', component: About } ] ``` - 通常會有很多路由,所以會獨立提出來寫,而非直接寫在`createRouter`裡 - 每個route中常用的有: - **path**: 進入該頁面的路徑。 - 例如: `path: ‘about’`,網頁網址為`http://localhost:12345`,則要進入此頁面則須輸入`http://localhost:12345/about` - **name**: 該路由的名稱。 - **component**: 該路由的元件。 - 例如: 上面的Home的元件取自`import Home from '../components/HelloWorld.vue’`,則當進入home頁面時,`HelloWorld.vue`就會載入至`<router-view></router-view>` - 除了先將元件載入再指派給route,也可等進入該頁面在加載該元件的方法。 - 例如: `component: ()⇒import('../components/HelloWorld.vue’)`。 - **meta**: 自定義的參數 - 例如: 該頁面的title,index等,並使用route.meta.title等來讀取。 - ****redirect: 進入該頁面時,重定向到指定的頁面。**** - **alias**: 路由的別名。 - 例如: `path: ‘/’,alias: ‘/home’`,則使用/或/home都匯到同意頁面。 - **beforeEnter**: 進入該路由之前做某些事,待下一節說明。 # 3. 導航守衛(****Navigation Guards****) - 分為 - beforeEach - beforeResolve - afterEach - beforeEnter - beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave ## 3.1 全域守衛 ### 3.1.1 beforeEach - 使用`router.beforeEach`來使用此守衛。 ```jsx const router = createRouter({ ... }) router.beforeEach((to, from) => { if(...){ return {name: "/"} }else if(...){ return '/' }else{ // ... // 返回 false 以取消導航 return false } }) ``` - 此守衛將在進入路由之前執行,但此時路由尚未解析,所以不可調用meta屬性。 - to: 即將進入的路由 - from: 即將離開的路由 - 如果return false,則取消路由,true或undefine則為成功 ### 3.1.2 beforeResolve ```jsx const router = createRouter({ ... }) router.beforeResolve((to, from) => { }) ``` - 此守衛與beforeEach類似,但beforeResolve是在路由解析完後才被調用的,所以可以使用meta屬性。 ### 3.1.3 afterEach ```jsx router.afterEach((to, from) => { sendToAnalytics(to.fullPath) }) ``` - 此守衛在導航成功後,頁面渲染前,被調用。 - 不能改變導航路徑 ## 3.2 路由內的守衛 ### 3.2.1 beforeEnter ```jsx const routes = [ { path: '/abc', component: Test, beforeEnter: (to, from) => { }, }, ] ``` - beforeEnter在進入該路由時被調用。 - 可使用函數傳遞: ```jsx function removeQueryParams(to) { if (Object.keys(to.query).length) return { path: to.path, query: {}, hash: to.hash } } function removeHash(to) { if (to.hash) return { path: to.path, query: to.query, hash: '' } } const routes = [ { path: '/users/:id', component: UserDetails, beforeEnter: [removeQueryParams, removeHash], }, { path: '/about', component: UserDetails, beforeEnter: [removeQueryParams], }, ] ``` ## 3.3 完整的導航流程 1. 導航被觸發。 2. 在要離開的元件裡調用守衛`beforeRouteLeave`。 3. 調用全域守衛`beforeEach`。 4. 在重用的元件裡調用守衛`beforeRouteUpdate`。 5. 在路由配置裡調用`beforeEnter`。 6. 解析異步路由元件。 7. 在被啟動的元件裡調用`beforeRouteEnter`。 8. 調用全域的守衛`beforeResolve`。 9. 導航被確認。 10. 調用全域的鉤子`afterEach`。 11. 觸發 DOM 更新。 12. 調用守衛中傳給的回調函數,創建好的元件實例會作為回調函數的參數傳入。`beforeRouteEnternext` # 4. 參考資料 [4-4 路由守衛(Navigation Guards) | 重新認識 Vue.js | Kuro Hsu](https://book.vue.tw/CH4/4-4-navigation-guards.html) [Navigation Guards | Vue Router](https://router.vuejs.org/guide/advanced/navigation-guards.html)