Vue中預設並不提供路由功能,需要安裝其外掛Vue-router,如下所示,其中「@3」表示安裝版本3
npm i vue-router@3
在src目錄下建立路由檔案目錄,目錄名為「router」,並在該目錄下建立「index.js」檔案,檔案內容如下所示,程式碼中,建立了一個路由器,其中設定了兩個路由「about」和「home」,分別對應元件「About」和「Home」。
// 該檔案專門用於建立整個應用的路由器
import VueRouter from 'vue-router'
//引入元件
import About from '../components/About'
import Home from '../components/Home'
//建立並暴露一個路由器
export default new VueRouter({
routes:[
{
path:'/about',
component:About
},
{
path:'/home',
component:Home
}
]
})
隨後,還需要在main.js檔案中引入並應用路由:
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入VueRouter
import VueRouter from 'vue-router'
//引入路由器
import router from './router'
//關閉Vue的生產提示
Vue.config.productionTip = false
//應用外掛
Vue.use(VueRouter)
//建立vm
new Vue({
el:'#app',
render: h => h(App),
router:router
})
在元件模板中,<router-link>
標籤實現跳轉,<router-view>
標註展現位置。<router-link>
標籤如下:
<router-link class="list-group-item" active-class="active" to="/about">About</router-link>
<router-link class="list-group-item" active-class="active" to="/home">Home</router-link>
<router-view>
標籤如下:
<router-view></router-view>
About.vue內容如下:
<template>
<h2>我是About的內容</h2>
</template>
<script>
export default {
name:'About'
}
</script>
Home.vue內容如下:
<template>
<h2>我是Home的內容</h2>
</template>
<script>
export default {
name:'Home'
}
</script>
完整App.vue程式碼如下:
<template>
<div>
<div class="row">
<div class="col-xs-offset-2 col-xs-8">
<div class="page-header"><h2>Vue Router Demo</h2></div>
</div>
</div>
<div class="row">
<div class="col-xs-2 col-xs-offset-2">
<div class="list-group">
<!-- 原始html中我們使用a標籤實現頁面的跳轉 -->
<!-- <a class="list-group-item active" href="./about.html">About</a> -->
<!-- <a class="list-group-item" href="./home.html">Home</a> -->
<!-- Vue中藉助router-link標籤實現路由的切換 -->
<router-link class="list-group-item" active-class="active" to="/about">About</router-link>
<router-link class="list-group-item" active-class="active" to="/home">Home</router-link>
</div>
</div>
<div class="col-xs-6">
<div class="panel">
<div class="panel-body">
<!-- 指定元件的呈現位置 -->
<router-view></router-view>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name:'App',
}
</script>
頁面效果如下圖所示:
在介紹頁面路由之前,我們先在src目錄下建立pages目錄,然後將About.vue和Home.vue等頁面元件,移動到pages目錄下,然後對main.js檔案內容進行對應修改。
新增Message.vue和News.vue兩個元件,Message.vue檔案內容如下:
<template>
<div>
<ul>
<li>
<a href="/message1">message001</a>
</li>
<li>
<a href="/message2">message002</a>
</li>
<li>
<a href="/message/3">message003</a>
</li>
</ul>
</div>
</template>
<script>
export default {
name:'Message'
}
</script>
News.vue檔案內容如下:
<template>
<ul>
<li>news001</li>
<li>news002</li>
<li>news003</li>
</ul>
</template>
<script>
export default {
name:'News'
}
</script>
因為Message.vue和News.vue兩個元件都是Home元件的子元件,所以Home.vue檔案內容也要進行修改,修改後內容如下:
<template>
<div>
<h2>Home元件內容</h2>
<div>
<ul class="nav nav-tabs">
<li>
<router-link class="list-group-item" active-class="active" to="/home/news">News</router-link>
</li>
<li>
<router-link class="list-group-item" active-class="active" to="/home/message">Message</router-link>
</li>
</ul>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name:'Home',
}
</script>
路面最終效果如下所示:
在某些場景下,路由也需要帶引數,例如上述例子中,Message元件下,點選message001、message002、message003時,可以附帶引數,實現跳轉後統一Detail元件下的不同內容場景。我們把Message元件內容改為如下所示,<router-link>
中to
引數改為v-bind繫結,其內容改為一個物件設定項,設定項中,path為路由,指向Detail元件,query為傳遞的傳輸。
<template>
<div>
<ul>
<li v-for="m in messageList" :key="m.id">
<!-- 跳轉路由並攜帶query引數,to的字串寫法 -->
<!-- <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{m.title}}</router-link> -->
<!-- 跳轉路由並攜帶query引數,to的物件寫法 -->
<router-link :to="{
path:'/home/message/detail',
query:{
id:m.id,
title:m.title
}
}">
{{m.title}}
</router-link>
</li>
</ul>
<hr>
<router-view></router-view>
</div>
</template>
<script>
export default {
name:'Message',
data() {
return {
messageList:[
{id:'001',title:'訊息001'},
{id:'002',title:'訊息002'},
{id:'003',title:'訊息003'}
]
}
},
}
</script>
Detail元件內容如下,通過元件範例下的$route.query
物件,可以讀取通過路由傳遞過來的引數:
<template>
<ul>
<li>訊息編號:{{$route.query.id}}</li>
<li>訊息標題:{{$route.query.title}}</li>
</ul>
</template>
<script>
export default {
name:'Detail',
mounted() {
console.log(this.$route)
},
}
</script>
Detail元件的路由,也需要在router/index.js
中重新設定:
// 該檔案專門用於建立整個應用的路由器
import VueRouter from 'vue-router'
//引入元件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'
//建立並暴露一個路由器
export default new VueRouter({
routes:[
{
path:'/about',
component:About
},
{
path:'/home',
component:Home,
children:[
{
path:'news',
component:News,
},
{
path:'message',
component:Message,
children:[
{
path:'detail',
component:Detail,
}
]
}
]
}
]
})
頁面效果如下圖所示:
vue中也可以使用param引數進行引數,這種方式比query方式更加優雅一些。使用這種方式是,在router/index.js
組態檔中,在對Detail元件設定path引數是,進行說明。千萬注意,在使用param方式進行傳參時,<router-link>
標籤內不能再使用path設定路由了,一定要使用name引數。:
// 該檔案專門用於建立整個應用的路由器
import VueRouter from 'vue-router'
//引入元件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'
//建立並暴露一個路由器
export default new VueRouter({
routes:[
{
name:'guanyu',
path:'/about',
component:About
},
{
path:'/home',
component:Home,
children:[
{
path:'news',
component:News,
},
{
path:'message',
component:Message,
children:[
{
name:'xiangqing',
path:'detail/:id/:title', // 此處進行設定,說明要接受id和title兩個引數
component:Detail,
}
]
}
]
}
]
})
在Massage.vue中,讀取param傳遞引數方式如下所示:
<template>
<div>
<ul>
<li v-for="m in messageList" :key="m.id">
<!-- 跳轉路由並攜帶params引數,to的字串寫法 -->
<!-- <router-link :to="`/home/message/detail/${m.id}/${m.title}`">{{m.title}}</router-link> -->
<!-- 跳轉路由並攜帶params引數,to的物件寫法 -->
<router-link :to="{
name:'xiangqing',
params:{
id:m.id,
title:m.title
}
}">
{{m.title}}
</router-link>
</li>
</ul>
<hr>
<router-view></router-view>
</div>
</template>
<script>
export default {
name:'Message',
data() {
return {
messageList:[
{id:'001',title:'訊息001'},
{id:'002',title:'訊息002'},
{id:'003',title:'訊息003'}
]
}
},
}
</script>
Detail元件中讀取資料的方式也要跟著變化:
<template>
<ul>
<li>訊息編號:{{$route.params.id}}</li>
<li>訊息標題:{{$route.params.title}}</li>
</ul>
</template>
<script>
export default {
name:'Detail',
mounted() {
// console.log(this.$route)
},
}
</script>
頁面效果如下圖所示:
在上述介紹query和param傳引數,我們都是使用$router.query
或$router.param
進行接收引數,每次接收引數都要寫這兩個物件,不免有些麻煩。為簡便程式碼,vue提供props進行接收引數,設定改引數後,所有路由傳遞的引數,都將以props的形式傳遞給元件。
在接收引數的元件設定路由時,新增props設定項,例如在設定Detail元件路由時,新增props設定項,書寫方式有三種,如下所示。注意,第二種方式只能用於param方式傳參,第三種方式最靈活,可同時運用於param和query方式傳參,也能新增其他引數。:
{
name:'xiangqing',
path:'detail',
// path:'detail/:id/:title',
component:Detail,
//props的第一種寫法,值為物件,該物件中的所有key-value都會以props的形式傳給Detail元件。這種方式用的很少,因為傳遞的引數是寫死的。
// props:{a:1,b:'hello'}
//props的第二種寫法,值為布林值,若布林值為真,就會把該路由元件收到的所有params引數,以props的形式傳給Detail元件。注意,這種方式只能用於param方式傳參。
// props:true
//props的第三種寫法,值為函數
props($route){
return {
id:$route.query.id,
title:$route.query.title,
a:1,
b:'hello'
}
}
}
當然,這時候在Detail也需要設定props引數:
<template>
<ul>
<li>訊息編號:{{id}}</li>
<li>訊息標題:{{title}}</li>
</ul>
</template>
<script>
export default {
name:'Detail',
props:['id','title'],
}
</script>
為路由命名可以簡化程式碼,方便維護。命名的方式也很簡單,在router/index.js
路由設定內,新增一個name
設定項即可,如下所示我們為About元件和Detail元件的路由進行命名:
// 該檔案專門用於建立整個應用的路由器
import VueRouter from 'vue-router'
//引入元件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'
//建立並暴露一個路由器
export default new VueRouter({
routes:[
{
name:'guanyu',
path:'/about',
component:About
},
{
path:'/home',
component:Home,
children:[
{
path:'news',
component:News,
},
{
path:'message',
component:Message,
children:[
{
name:'xiangqing',
path:'detail',
component:Detail,
}
]
}
]
}
]
})
命名後,我們可以對<router-link>
標籤進行改寫,例如,Message.vue檔案中的<router-link>
標籤改為如下:
<router-link :to="{
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
}">
App.vue中的跳轉到About元件的<router-link>
標籤改為如下:
<router-link class="list-group-item" active-class="active" v-bind:to="{name: 'guanyu'}">About</router-link>
<router-link>
的replace屬性¶<router-link>
的replace屬性可以控制路由跳轉時操作瀏覽器歷史記錄的模式。瀏覽器的歷史記錄有兩種寫入方式,push
和replace
模式,push
是追加歷史記錄,replace
是替換當前記錄,路由跳轉時候,預設是push
。當開啟replace
時,不可後退到前一條記錄。
開啟replace
的方式是在<router-link>
標籤中,新增replace
屬性,並將值設定為true。
<router-link replace="true">Home</router-link>
<!--也可以進行簡寫:-->
<router-link replace>Home</router-link>
上文所述多有範例,都是用用<router-link>
來實現跳轉,<router-link>
標籤在解析後都會轉化為a標籤。但是,在許多場景中,我們需要使用其他標籤來實現跳轉,例如,點選按鈕之後實現跳轉。這種情況下,就可以使用元件範例的$router.push
和$router.replace
兩個方法來實現跳轉。區別在於$router.push
可以在瀏覽器中進行回退,而$router.replace
不能回退。
<template>
<div>
<ul>
<li v-for="m in messageList" :key="m.id">
<p>{{m.title}} <button @click="showDetail(m.id, m.title)">點選顯示詳情頁</button></p>
</li>
</ul>
<hr>
<router-view></router-view>
</div>
</template>
<script>
export default {
name:'Message',
data() {
return {
messageList:[
{id:'001',title:'訊息001'},
{id:'002',title:'訊息002'},
{id:'003',title:'訊息003'}
]
}
},
methods: {
showDetail(id, title){
this.$router.push({ // 實現push方式跳轉
name: 'xiangqing',
query:{
id,
title
}
})
}
},
}
</script>
當然,$router
也提供了其他功能函數,例如$router.forward
和$router.back
分別用於操作瀏覽器記錄進行前進和回退,這裡不再演示。
在一些元件裡,存在輸入框,當我們輸入文字之後,如果進行前進或者後退操作,那麼輸入框的內容就會被清空。怎麼在前進後退操作過程中保留輸入記錄呢?這就需要使用到快取路由元件技術了:在父元件模板中用<keep-alive>
標籤將需要快取的子元件標籤包裹。例如,我們在News元件中新增一些輸入框,並輸入一些內容,如果需要快取這些內容,使得後續前進、後退跳轉過程中,這些內容依然存在,那麼就需要在App元件的模板中,使用<keep-alive>
將顯示News的<router-view>
標籤包裹,內容如下:
<keep-alive include="News">
<router-view></router-view>
</keep-alive>
<keep-alive>
中可以使用include屬性指定需要快取的子元件(多個元件用陣列指定),也可以不指定,另外,也可以用exclude來指定不需要快取的元件,如果都不指定,表示快取內部需要顯示的所有子元件。
但是注意,如果點選「About」然後在回到「Home-News」,輸入的內容就不再了,因為快取只針對於Home的子元件,點選「About」然後在回到「Home-News」時,Home元件都已經被銷燬再重新範例化,所以輸入的內容就不可能存在了。
作者:奧辰
微訊號:chb1137796095
Github:https://github.com/ChenHuabin321
歡迎加V交流,共同學習,共同進步!
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結,否則保留追究法律責任的權利。