使用Vue Router 及配置路由文件 以上範例,你可以看到它們都是停留在index的網址上, 但是,會因為我們在#後面所接入的內容不同,來呈現不同元件的內容。 像上面圖片是#/user,所以,此時是呈現 user 元件。 像下面圖片是#/product,所以,此時是呈現 product 元件。
故本節是紀錄怎麼建立Vue Router
Router會包含幾個檔案
首先,進入點 包含它會注入src資料夾中的元件檔和其他的component檔案。
第二,新增路由的配置檔案 這個配置檔案會決定在哪個路由中呈現哪個元件檔案。 那它執行的路徑會在router/index.js 中。
第三,分頁內容
Vue Components 就是一些元件的檔案,例如專案檔中的Hellowolrd.vue檔。
接下來,介紹安裝vue 的router步驟 step1. 先輸入 npm install vue-router --save
指令
step2. 在src資料夾中,新建一個叫router的資料夾 在router下再新增一個叫index.js的檔案,這個檔案就是要放整個路由的配置檔。
step3. 在index.js檔案中輸入import Vue from 'vue'
import VueRouter from 'vue-router'
以上這兩行呢,是將官方提供的元件給引入進來。
接下來,在這兩行之後就是引入我們自己的元件囉。import Home from '@/component/HelloWorld'
引入在src資料夾中的HelloWorld元件檔,並將它命名為Home
step4. 在你引入完官方元件 和你自己的元件檔之後, 就是要輸入啟用的指令, 那你就在同一個index.js檔案中,在引入程式碼的後方輸入Vue.use(VueRouter)
ex:
1 2 3 4 5 6 7 import Vue from 'vue' import VueRouter from 'vue-router' // 以上為官方提供的元件 import Home from '@/component/HelloWorld' Vue.use(VueRouter) // 啟用指令
step5. 因為這個檔案,我們必須匯出給entry
使用, 所以,我們要再加上以下的程式碼
1 2 3 4 5 6 7 8 9 10 import Vue from 'vue' import VueRouter from 'vue-router' // 以上為官方提供的元件 import Home from '@/components/HelloWorld' Vue.use(VueRouter) export default new VueRouter({ });
你可以看到我們在最下面,輸入了export
的相關內容。
step6. 在main.js檔案中,匯入你的router檔案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ---main.js檔案--- // The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import axios from 'axios' import VueAxios from 'vue-axios' import router from './router' // 匯入router檔案 Vue.use(VueAxios, axios) Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', components: { App }, template: '<App/>', router, // 新增router屬性 })
你可以看到我們在main.js檔案中匯入了router檔案, 並在vue物件新增了一個router屬性
step7. 運行npm run dev
來執行vue的環境吧 此時,你運行http://localhost:8080 應該會發現你的網址後面新增了#,而這個#後面就是你的虛擬路由器
step8. 接著,你就去index.js中的export default new VueRouter
內容新增以下的內容 ex:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import Vue from 'vue'; import VueRouter from 'vue-router'; // 以上為官方提供的元件 import Home from '@/components/HelloWorld' Vue.use(VueRouter); export default new VueRouter({ routes:[ { name:'首頁',//元件呈現名稱 path:'/', //對應虛擬的路徑 component:Home , //它所對應的原件 } ] });
step9. 接著你去App.vue檔案中的template
部分, 新增以下的<router-view></router-view>
並把原本的<Helloworld>
元件的部分註解掉
1 2 3 4 5 6 7 8 <template> <div id="app"> <img src="./assets/logo.png"> <!--<HelloWorld/>--> <router-view></router-view> <button class="btn btn-danger">按鈕</button> </div> </template>
接著,你在畫面上應該是看不出來有啥差別,此時,你就打開vue開發者工具, 你去看App底下的HelloWolrd元件的標籤旁邊,應該就會跟著一個router-view的標籤喔。
接下來我們要新增另一個元件, step1. 接著,我們先偷懶在最外層的index.html引入bootstrap的CSS的CDN。
step2. 我們在components資料夾中,新增一個pages的資料夾 在這個pages資料夾中新增一個pages.vue的元件檔
step3. 我們去bootstrap中的card
元件內容複製,並貼到pages.vue的template
中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <template> <div> <div class="card" style="width: 18rem;"> <img src="" class="card-img-top" alt="..."> <div class="card-body"> <h5 class="card-title">Card title</h5> <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p> <a href="#" class="btn btn-primary">Go somewhere</a> </div> </div> </div> </template> <script> export default { name: 'pages', data () { return{ } } } </script>
以上的內容你就可以看到,我們在pages中的template
加入了card
元件的內容。
注意,元件外面要再包一個div 老師建議,你在創任何元件的template
的時候,它們的內容外面都要再包一層div
, 是因為Vue 最外層的元素不能直接使用 vue 的指令。 ex:
1 2 3 <template> <div v-for="..."></div> </template>
像上面這樣,如果你直接對最外層使用v-for
指令的話,就會出錯喔。
step4. 接著,你去index.js檔案裡面,新增引入pages元件的相關設定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import Vue from 'vue'; import VueRouter from 'vue-router'; import Home from '@/components/HelloWorld' import Page from '@/components/pages/pages' // 引入pages.vue元件 Vue.use(VueRouter); export default new VueRouter({ routes:[ { name:'首頁', path:'/index', component:Home , }, { // 新增pages元件的相關設定 name:'分頁', path:'/page', component:Page , } ] });
step5. 接著,你將你的vue的網址的#號後面,加入Page 即:http://localhost:8080/#/Page
此時,你應該就可以看到在網頁上看到新增的 Page 元件的內容。
製作分頁的切換 接下來要接分頁的切換 step1. 首先我們先為 App.vue 元件檔引入 bootstrap 的 navbar
內容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ---App.vue 元件檔--- <template> <div id="app"> <!--navbar開始--> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <div class="container-fluid"> <a class="navbar-brand" href="#">Navbar</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav me-auto mb-2 mb-lg-0"> <li class="nav-item"> <a class="nav-link active" href="#">Home</a> </li> <li class="nav-item"> <a class="nav-link" href="#">Page</a> </li> </ul> </div> </div> </nav> <!--navbar結束--> <img src="./assets/logo.png"> <router-view></router-view> <button class="btn btn-danger">按鈕</button> </div> </template>
你可以看到,我們在template
中,加入了navbar
樣式,此時,你刷新網頁後, 應該就會出現navbar
的樣式了。
step2. 接著,我們修改在App.vue的檔案中,連動到Home和Page的a
標籤,將其改成router-link
標籤,並在這些標籤內分別加入to="/index"和to="/Page"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 ---APP.vue檔案--- <template> <div id="app"> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <div class="container-fluid"> <a class="navbar-brand" href="#">Navbar</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav me-auto mb-2 mb-lg-0"> <li class="nav-item"> <router-link class="nav-link active" to="/index">Home</router-link> // 轉換到 Home 的按鈕 </li> <li class="nav-item"> <router-link class="nav-link" to="/Page">Page</router-link> // 轉換到 Page 的按鈕 </li> </ul> </div> </div> </nav> <img src="./assets/logo.png"> <router-view></router-view> <button class="btn btn-danger">按鈕</button> </div> </template>
此時,你點擊 Home 和 Page 按鈕的時候,應該就跳轉到 Home 或 Page 的頁面囉,所以,在 index.js 中,各物件的 path 屬性,就是用在跳轉分頁路徑做使用。
除了to以外,還有其他跳轉頁面的方法 就是使用在index.js中,你為那些元件檔所加入的name
的屬性名稱。 所以,就將App.vue中的navbar
做以下的修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <template> <div id="app"> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <div class="container-fluid"> <a class="navbar-brand" href="#">Navbar</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav me-auto mb-2 mb-lg-0"> <li class="nav-item"> <router-link class="nav-link active" :to="{name:'首頁'}">Home</router-link> // 換成name的屬性名稱 </li> <li class="nav-item"> <router-link class="nav-link" to="/Page">Page</router-link> </li> </ul> </div> </div> </nav> <img src="./assets/logo.png"> <router-view></router-view> <button class="btn btn-danger">按鈕</button> </div> </template>
你可以看到,在首頁的router-link
標籤部分,我們把to
的屬性用v-bind
去動態綁定name
屬性,並將這個屬性名稱改成這個元件的name
的名稱,如此,就可以跟原本的to
達成一樣的切換頁面效果囉。
製作巢狀路由頁面 首先,我們在pages同一層的目錄中,分別建立三個元件檔child.vue, child2.vue, child3.vue 接著,你要特別注意一點, 在這三個元件檔child.vue, child2.vue, child3.vue中的card元件是不包含最外層的card。 那在pages檔案中,就只有保留最外層的.card的div
, 因為,我們希望透過切換child.vue, child2.vue, child3.vue 來變換pages.vue中,.card裡面的內容。 所以,要改成像下面這樣 即:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ---child.vue檔案--- <template> <div> <img src="" class="card-img-top" alt="..."> <div class="card-body"> <h5 class="card-title">Card 1</h5> <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p> <a href="#" class="btn btn-primary">Go somewhere</a> </div> </div> </template> ---pages.vue檔案--- <template> <div> <div class="card" style="width: 18rem;"> <router-view><router-view> </div> </div> </template>
你可以看到,我們在pages的元件裡面,在想要替換內容的部分,加入<router-view></router-view>
,藉此,透過router的方式,來變換card.vue, card2.vue, card3.vue的內容。
step2. 我們回到index.js檔案中, 我們先將child.vue, child2.vue, child3.vue 這三個元件檔引入到index.js檔案裡面。
1 2 3 import child_1 from '@/components/pages/child' import child_2 from '@/components/pages/child2' import child_3 from '@/components/pages/child3'
step3. 在pages的元件內容中,加入children
的屬性,並把child.vue, child2.vue, child3.vue的路徑相關設定塞進去
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 export default new VueRouter({ routes:[ { name:'首頁', path:'/index', component:Home }, { name:'分頁', path:'/page', component:Page, children:[ // 插入巢狀路由內容 { name:'child1', path:'', component:child_1 }, { name:'child2', path:'child2', component:child_2 }, { name:'child3', path:'child3', component:child_3 } ] } ] });
你可以看到,我們對Page又加了一個children
屬性,並在裡面加了要引入的元件。 而你可以特別注意到,我們沒有對child1的path
設值,這是因為,我們把它當為Page內容的預設值,也就是說Page元件<router-view>
裡面的內容,預設會是card1的內容。
step4. 製作切換card1, card2, card3的內容 首先,我們就到pages.vue檔案中,加入<router-link></router-link>
的元件,並透過to
的方式來切換它們之間的內容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <template> <div> <router-link to="/page">卡片一</router-link> <router-link to="/page/child2">卡片二</router-link> <router-link to="/page/child3">卡片三</router-link> <div class="card" style="width: 18rem;"> <router-view></router-view> </div> </div> </template> <script> export default { name: 'HelloWorld', data () { return{ } } } </script>
你可以看到,我們新增了三個router-link
,並在這些標籤裡面,加入了to
屬性,也就是它要跑去哪個頁面的路徑。
注意,元件檔絕對路徑的引用 你看上面router-link
是直接用/page/child2 ,是用絕對路徑來引用元件檔。 不要用相對路徑來引入元件,即page/child2,這樣容易造成路徑檔案引用錯誤,要特別小心。
使用動態路由切換頁面 Ajax 結果 這個動態路由的功用就在於 透過動態路由來載入不同的內容,並將這些內容加到固定的版型中。
加入動態路由 首先,我們先到index.js檔案中,對card3的元件內容的path
屬性做調整
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 export default new VueRouter({ routes:[ { name:'首頁', path:'/index', component:Home }, { name:'分頁', path:'/page', component:Page, children:[ { name:'child1', path:'', component:child_1 }, { name:'child2', path:'child2', component:child_2 }, { name:'child3', path:'child/:id', // 動態路由 component:child_3 } ] } ] });
接著,你去按頁面上卡片三的按鈕,此時,頁面應該是會失效的。 那你就把原本的卡片三路徑http://localhost:8080/#/page/child3 改成http://localhost:8080/#/page/child/ffff
這個時候,頁面應該就會呈現 child3 的內容囉。
取得動態路由內容 step1. 我們先取得我們剛剛修改的動態路由的id
。 你先去child3.vue的元件檔中,新增created
的hook,並透過log
來看看它的id
是什麼
1 2 3 4 5 6 7 8 9 10 11 12 13 <script> export default { name: 'HelloWorld', data () { return{ } }, created:function(){ console.log(this.$route.params.id); // 取得它的id內容 } } </script>
透過以上的語法,我們可以在 child3.vue 元件創建的時候,取得該元件路由中的 id 屬性值。
搭配vue.axios的功能 那為什麼要取得這個router的id
呢,因為,要把它跟axios一起使用。 以下內容為 child3.vue 加入 axios 來取得 api 的內容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ---child3.vue元件檔--- <script> export default { name: 'HelloWorld', data () { return{ } }, created:function(){ console.log(this.$route.params.id); this.$http.get('https://randomuser.me/api/').then((response) => { console.log(response) }) } } </script>
如此,就能取得api的結果。
那在這個random產出api的網址中,有一個seeds的功能,它可以產出固定api的內容。 那我們就可以藉由動態路由的方式,來存取同一份資料囉。 修改一下 child3.vue 的內容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ---child3.vue元件檔--- <script> export default { name: 'HelloWorld', data () { return{ } }, created:function(){ var id = this.$route.params.id; this.$http.get(`https://randomuser.me/api/?seed=${id}`).then((response) => { console.log(response) }) } } </script>
你用以上的寫法,就可以藉由console.log
中的data裡面的內容,在每一次頁面刷新的時候, 都是相同的喔。
命名路由,同一個路徑載入兩個頁面元件 假設在同一個畫面下,要執行兩個router-view
。
在App.vue檔案中, 我們在新增的.container的裡面跟外面分別加入<router-view></router-view>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <template> <div id="app"> <nav class="navbar navbar-expand-sm navbar-light bg-light"> <div class="container-fluid"> <a class="navbar-brand" href="#">Navbar</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav me-auto mb-2 mb-lg-0"> <li class="nav-item"> <router-link class="nav-link active" :to="{name:'首頁'}">Home</router-link> </li> <li class="nav-item"> <router-link class="nav-link" to="/Page">Page</router-link> </li> </ul> </div> </div> </nav> <router-view name="menu"></router-view> // 新增 router-view <div class="container"> <router-view></router-view> // 新增 router-view </div> </div> </template>
你可以看到在.container裡面有一個router-view
,它是吃預設的樣式。 外層也有一個router-view
,我們特別為它的name
屬性命名為menu。
step2. 接著,我們在page.vue的同一層目錄中,新增另一個menu.vue的元件檔。 並且,我們將原本寫在App.vue的router-link
內容,都移到menu.vue元件檔中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ---menu.vue元件檔--- <template> <div> <nav aria-label="breadcrumb"> <ol class="breadcrumb"> <li class="breadcrumb-item"> <router-link to="/page">卡片一</router-link> </li> <li class="breadcrumb-item"> <router-link to="/page/child2">卡片二</router-link> </li> <li class="breadcrumb-item active" aria-current="page"> <router-link to="/page/child3">卡片三</router-link> </li> </ol> </nav> </div> </template> <script> export default { name: 'menu', data () { return{ } } } </script>
你可以看到,我們把那些router-link
從page.vue檔案中,抓來menu.vue檔。 所以,此時,page.vue元件檔,只會剩下.card的部分。
step3. 接著,我們到index.js檔案中,去匯入剛剛新增的menu.vue元件檔 並在routes使用components
,來同時匯入Page和menu這兩個元件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 import Vue from 'vue'; import VueRouter from 'vue-router'; import Home from '@/components/HelloWorld' import Page from '@/components/pages/pages' import child_1 from '@/components/pages/child' import child_2 from '@/components/pages/child2' import child_3 from '@/components/pages/child3' import Menu from '@/components/pages/menu' // 匯入Menu元件 Vue.use(VueRouter); export default new VueRouter({ routes:[ { name:'首頁', path:'/index', component:Home }, { name:'分頁', path:'/page', //component:Page, // 原本只有引用 Page 元件 components:{ default: Page, menu: Menu, // 加入 Menu 元件 }, children:[ { name:'child1', path:'', component:child_1 }, { name:'child2', path:'child2', component:child_2 }, { name:'child3', path:'child3', component:child_3 } ] } ] });
你可以看到components
屬性是一個物件,然後它裡面有兩個屬性default
的值是Page,也就是Page元件, 而menu的值是Menu,也就是我們剛剛製作的Menu元件囉, 那要注意一下,這個menu的屬性名稱,要跟你在App.vue元件中, 你為那個在.container外層的router-view
所加入的name
屬性的值menu一樣喔。
經過以上的步驟,你應該就可以成功地在Page頁面上,同時呈現兩個不同的router-view
元件囉。
修正小錯誤 以上的範例你可以知道,page元件的內容預設是吃到child1的內容, 但是,瀏覽器上會跳以下這個錯誤
它是說 page 分頁中,已經有預設的元件了,就是 child1 元件,會造成 child1 元件的內容不會被渲染出來。 所以,要移除 page 元件的name 的屬性內容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 ---router資料夾中的index.js檔案--- export default new VueRouter({ routes:[ { name:'首頁', path:'/index', component:Home }, { //name:'分頁', // 元件呈現名稱 -- 註解掉 path:'/page', //component:Page , // 它所對應的原件 components:{ default: Page, menu: Menu, }, children:[ { name:'child1', path:'', component:child_1 }, { name:'child2', path:'child2', component:child_2 }, { name:'child3', path:'child3', component:child_3 } ] } ] });
你看,我們將 page 元件檔的 name:’分頁’的部分註解掉,之後,上面那個錯誤就不會再出現囉~~