路由
<body>
<div id="box">
<div>
<router-link to="/home">Home</router-link>
<!--router-link用來展示組件導航-->
<!--to屬性用于指定鏈接-->
<!--<router-link>標簽會默認被渲染成a標簽-->
<!--當前被點擊的路由會自帶.router-link-active屬性-->
<router-link to="/news">News</router-link>
</div>
<div>
<!--路由出口,路由默認會被渲染在這里-->
<router-view></router-view>
</div>
</div>
</body>
<script>
//創建路由組件
var Home = {
template: "<h4>我是主頁</h4>"
},
News = {
template: "<h4>我是新聞</h4>"
};
//定義組件
var routes=[
{path:"/home",component:Home},
{path:"/news",component:News},
{path:"*",redirect:"/home"}
]
//創建路由實例,配置路由實例
var router=new VueRouter({
routes:routes,
linkActiveClass:"color"
})
//創建并將路由掛載到根實例
new Vue({
el:"#box",
router:router
})
</script>
動態路由匹配
我們經常需要把某種模式匹配到的所有路由,全部映射到同一個組件,例如我們有一個user組件用來展示用戶信息,那么對于不同ID的用戶,我們都需要使用這個組件來渲染,那么我們就可以在vue-router的路由路勁中使用動態路徑參數來達到這個效果
body>
<div id="box">
<div>
<router-link to="/home/1">Home</router-link>
<router-link to="/home/2">News</router-link>
</div>
<div>
<router-view></router-view>
</div>
</div>
<template id="home">
<div>
<h4>this's homr</h4>
</div>
</template>
<template id="news">
<div>
<h4>this's news</h4>
</div>
</template>
<script>
var Home = {
template: "#home"
},
News = {
template: "#news"
};
var routes=[
{path:"/home/:id",component:Home},
{path:"/news",component:News}
];
//在routes中路徑參數使用:標記,那么在匹配路由時,所有 /home/參數 格式的路徑都會被匹配到Home組件,當然也可以同時使用一個或多個 例如 /home/:id/name/:id 路徑參數使用:標記那么表示這個參數可以是任意值,:id的作用只是一個占位符,也可以使用正則來匹配,如:/:id(\\d+)
var router=new VueRouter({
routes:routes
});
new Vue({
el:"#box",
router:router
})
//在路由中設置多段路徑參數,對應的值都會設置到$route.params中,例如:
// /user/:username匹配到路徑/user/tom,那么我們可以通過$router.params獲取到{username:"tom"}
</script>
</body>
當我們使用路由參數時,例如從/user/foo跳轉到/user/bar時,原來的組件會被復用,這樣更加高效,但是同時也意味著組件的生命周期函數不是再被調用,如果想要對路由參數的變化做出響應的話,可以所使用watch監測$route對象
<script>
var User = {
template: "#user",
watch:{
'$route'(to,from){
console.log(to);
console.log(from);
//to表示從哪個路由開始跳轉
//from表示跳轉到哪個路由
//在跳轉時會觸發$route函數
}
}
}
</script>
路由嵌套
實例一
<body>
<div id="box">
<div>
<router-link to="/home">Home</router-link>
<router-link to="/news">News</router-link>
</div>
<div>
<router-view></router-view>
</div>
</div>
<template id="home">
<div>
<h4>this's home</h4>
<ul>
<li>
<router-link to="/home/tom">Tom</router-link>
<router-link to="/home/aix">Aix</router-link>
</li>
<li>
<router-view></router-view>
</li>
</ul>
</div>
</template>
<template id="news">
<div>
<h4>this's news</h4>
</div>
</template>
<script>
var Home = {
template:"#home"
},
News = {
template: "#news"
},
Tom={
template:`
<p>my name's tom</p>
`
},
Aix={
template:`
<p>my name's aix</p>
`
};
var routes=[
{
path:"/home",
component:Home,
children:[
{
path:"tom",
component:Tom
},
{
path:"aix",
component:Aix
}
]
},
{path:"/news",component:News}
]
var router=new VueRouter({
routes
})
new Vue({
router
}).$mount("#box")
</script>
</body>
實例二
<body>
<div id="box">
<div>
<h5>
<router-link to="/user/foo">A</router-link>
<router-link to="/user/foo/bar">B</router-link>
<router-link to="/user/foo/cat">C</router-link>
</h5>
<router-view></router-view>
</div>
</div>
<script>
const User = {
template: `
<div>
<p>{{$route.params.id}}</p>
<router-view></router-view>
</div>
`
}
const userHome = {
template: `
<div>Home</div>
`
}
const bar = {
template: `
<div>A</div>
`
}
const cat = {
template: `
<div>
<div>{{$route.matched}}</div>
<div>B</div>
</div>
`
}
const router = new VueRouter({
routes: [
{
path: "/user/:id",
component: User,
children: [
{path: "", component: userHome},
{path: "bar", component: bar},
{path: "cat", component: cat}
]
}
]
})
new Vue({
router
}).$mount("#box")
</script>
</body>
編程式導航
在vue中我們除了使用<router-link>創建a標簽來定義導航鏈接,還可以杰作router的實例方法,通過編寫代碼來實現,我們使用router-link標簽時,實際在內部會調用router.push方法,所以說點擊<router-link :to="/home">等同于調用router.push("/home")
<body>
<div id="box">
<div>
<li @click="home">Home</li>
<li @click="news">News</li>
</div>
<div>
<router-view></router-view>
</div>
</div>
<script>
const Home = {
template: `
<div>
<h3>this's Home</h3>
</div>
`
};
const News = {
template: `
<div>
<h3>this's News</h3>
</div>
`
};
const router = new VueRouter({
routes: [
{path: "/home", component: Home},
{path: "/news", component: News}
]
})
new Vue({
router,
methods: {
home() {
router.push("/home")
},
news() {
router.push("/news")
}
}
}).$mount("#box")
</script>
</body>
-
router.push()
該方法回想histiry棧添加一個新的記錄,所以當用戶點擊瀏覽器后退按鈕時,會回到之前的URL
-
router.repalce()
該方法和router.push相似,唯一不同在于,它不會向history添加新紀錄,而是替換掉當前的history記錄,所以用戶不能點擊瀏覽器后退按鈕,該方法相當于<router-link :to="..." replace>
-
router.go(n)
該方法的參數是一個整數,意思實在history記錄中向前或者后退多掃不,類似window.history.go(n),如果瀏覽器history記錄本身小于n,那么會失敗,并且不會返回失敗信息
push以及replate的參數可以是一個字符串路徑,或則一個描述的對象:
//字符串
router.push("/home")
//對象
router.push({psth:"/home"})
//命名的路由
router.push({name:"user",params:{userId:123}})
//帶查詢參數,變成/register?plan=private
router.push({path:'register',query:{plan:'private'}})
命名路由
有時候,通過一個名稱來表示一個路由顯的更方便一些,特別是在鏈接一個路由或執行一些跳轉的時候,我們可以在創建Router實例的時候,在routers配置中給某個路由設置名稱
<body>
<div id="box">
<div>
<router-link :to="{name:'home',params:{homeId:123}}">Hmoe</router-link>
<!--params表示傳入的動態路由homeId的參數123,該參數會傳入到路由的url地址中-->
<router-link :to="{name:'news'}">ews</router-link>
</div>
<div>
<router-view></router-view>
</div>
</div>
<script>
const Home = {
template: `
<div>
<h5>this's Home</h5>
</div>
`
},
News = {
template: `
<div>
<h5>this's News</h5>
</div>
`
};
var router = new VueRouter({
routes: [
{
path: "/home/:homeId",
name: "home",
//在router中為路由設置名稱后,在router-link中:to 直接接受路由名稱即可
component: Home
},
{
path:"/news",
name:"news",
component:News
}
]
})
new Vue({
router
}).$mount("#box")
</script>
</body>
命名視圖
如果我們想要同時在統計展示多個視圖,而不是嵌套展示,例如創建一個布局,有導航欄和主內容兩個視圖,我們可以使用命名視圖,利用命名視圖我們可以在界面中擁有多個單獨命名的視圖,而不是只有一個單獨的出口,如果router-view標簽沒有設置名字,那么默認為default
<style>
.nav {
width: 100%;
height: 40px;
color: forestgreen;
}
.main {
width: 100%;
height: 100px;
color: forestgreen;
border: 1px solid #000;
}
</style>
</head>
<body>
<div id="box">
<div>
<router-link to="/nav">Nav</router-link>
<router-link to="/main">Main</router-link>
</div>
<div>
<router-view name="navView" class="nav"></router-view>
<router-view name="mainView" class="main"></router-view>
</div>
</div>
<script>
const Nav = {
template: `
<div>
<h5>this's nav</h5>
</div>
`
},
Main = {
template: `
<div>
<h5>this's main</h5>
</div>
`
};
const router=new VueRouter({
routes:[
{
path:"/nav",
components:{
"navView":Nav
}
},
{
path:"/main",
components:{
"mainView":Main
}
}
]
})
new Vue({
router
}).$mount("#box")
</script>
</body>
重定向和別名
重定向是指將當前路由的指向重新定位到其它路由上,使用redirect來實現
const router=new VueRouter({
routes:[
{path:"/a",
redirect:"/b"}
//此時的/a的路由點擊會被重定向到/b路由上
]
})
//一般我們使用重定向來進行初始化頁面的展示
{ path:"*",redirect:"/b"}
//重定向也可以傳入一個路由名稱
{path:"/a",redirect:"{name:'b'}"}
別名和重定向的大致作用是類似的,但是區別在與
使用重定向時當用戶訪問/a時,匹配路由為/b,URL地址中也會被替換為/b
使用別名時當用戶訪問/a時,匹配的路由為/b,但是URL地址中不會被替換,依然是/a,就像用戶訪問/a一樣
const router=new VueRouter({
routes:[
path:"/a",
alias:"/b"
]
})
導航鉤子
vue-router提供了導航鉤子主要用來攔截導航,或則完成跳轉或取消,vue-router的導航鉤子會在路由發生改變時執行,有多種方式可以在路由發生改變時執行鉤子:全局的,單個路由獨享的,或者是組件級的
-
全局鉤子
使用router.beforeEach注冊一個全局的before鉤子
const router=new VueRouter({...}) router.beforeEach((to,form,next)=>{ ..... })
當一個導航觸發時,全局的before鉤子會按照創建順序調用,鉤子是異步解析執行,此時導航在所有鉤子執行完之前一直處于等待中
每個鉤子接收三個參數:
- to 表示將要進入的目標路由對象
- form 表示當前導航將要離開的路由
- next 如果了解node的話可以理解為node中的next()中間件,next()表示進行下一個導航,next(false)表示中斷當前的導航,也就是不再執行下一個跳轉導航的操作,next("/")或者next({path:"/",...})表示跳轉到我們指定的導航
一定要注意,一定要調用next()方法,否則之后的操作都不會被執行
同樣可以注冊一個全局的after鉤子,不過它沒有next方法,不能改變導航
router.afterEach(function (to,form) { console.log(to); console.log(form); alert("離開"+form.fullPath+",進入"+to.fullPath); })
-
單個路由的鉤子
通過為單個路由設置beforeEnter方法,該方法接收的參數和beforeEach是一樣的
const router = new VueRouter({ routes: [ { path: "/home", component: Home, children: [ { path: "info", component: Info, meta: { requiresAuth: true,age:18 }, beforeEnter:function (to,form,next){ console.log(to); console.log(form); next(); } }, {path: "set", component: Set} ] }, {path: "/news", component: News} ] })
同樣需要注意一定調用next(),否則不會進入到該導航
-
組件內的鉤子
也可以在路由組件內直接定義導航鉤子
- beforeRouteEnter
- beforeRouteUpdata(2.2)
- beforeRouteLeave
News = {
template: `
<div>
<h4>this's News</h4>
</div>
`,
data() {
return {
msg: 1
}
},
beforeRouteEnter: function (to, form, next) {
//注意在這里不能調用實例的this,因為該方法是在組件被創建之前調用的,所以此時實例是不存在的
next(vm => {
console.log(vm.$data.msg);
});
//但是可以通過為next傳入一個回調,把組件實例作為回調參數的方法來訪問組件的實例
},
beforeRouteUpdate:function (to,form,next) {
//該方法只有在當前組件被復用時會調用
//例如,對于一個帶有動態參數的路徑,foo/:id,在foo/1和foo/2之間跳轉的時候
//由于會渲染同樣的foo組件,因此逐漸實例會被復用,而這個鉤子會被調用,類似動態組件中的watch
//可以訪問實例的this
},
beforeRouteLeave:function(to,form,next) {
//在導航離開組件的對應路由時調用
//可以訪問組件實例this
//這個鉤子通常用于在用戶還未保存修改錢突然離開,可以通過next(false)來取消導航
}
}
路由元信息
定義路由的時候可以定義路由的meta字段,在meta中定義的字段,可以在路由記錄中獲取,可以用來對對每個路由進行配置,在vue中,我們稱呼router配置中的每個路由對象為路由記錄,路由記錄可以是嵌套的,因此,當一個路由匹配成功后,它可能匹配多個路由記錄,例如我們匹配到/foo/bar這個URL將會匹配副路由記錄以及自路由記錄,一個路由匹配到的所有路由記錄會暴露為$route.matched數組,因此,我們可以遍歷$$router.matched來檢查路由記錄中的meta字段
const router = new VueRouter({
routes: [
{
path: "/home",
component: Home,
children: [
{
path: "info",
component: Info,
meta: {
requiresAuth: true,
title:"主頁"
}
},
{path: "set", component: Set}
]
},
{path: "/news", component: News}
]
})
...........
router.beforeEach((to,form,next)=>{
if(to.matched.some(record => record.meta.requiresAuth)){
//if的判斷條件是用來判斷meta中設置的requiresAuth變量是否為true
//可以用來判斷該頁面是否需要用戶登錄才能進入該頁面
//如果我們設置一個路由的meta中requiresAuth變量為true,在全局路由鉤子函數執行的時候都會進入if判斷
console.log(to.matched.some(record => record.meta.requiresAuth));//true
//meta中設置的值也可以用來保存該路由中的信息,例如在meta中設置title屬性和值,在進入該頁面的時候獲取該title值設置到頁面中等操作
document.getElementById("test").innerText=to.meta.title;
if(用戶沒有登錄){
next("/login"); //跳轉到登錄頁面
}else {
next()
}
}else{
next()
//如果該頁面不需要登錄操作,執行用戶操作
}
})
注意,在to和form中我們可以獲取到跳轉的路由的信息,下面是打印的to的信息:
{name: undefined, meta: {…}, path: "/home/info", hash: "", query: {…}, …}
滾動行為
使用前端路由,當我們切換到新路由時,想要頁面滾動到頂部,或者是保持原先的滾動位置,就像重新加載頁面那樣,vue-router提供了更好的方法來讓自定義路由切換頁面是如何滾動
注意,這個功能只在HTML5 history模式下可用
在創建一個router實例的時候,可以提供一個scrollBehavior方法,該方法會在用戶進行路由切換時觸發
const router=new VueRouter({
routes:[
{
path:"/",
component:Home
}
],
scrollBehavior(to,form,savedPosition){
//scrollBehavior方法接收to,form路由對象,第三個參數savedPosition當且僅當在瀏覽器前進后退按鈕觸發時才可用
//該方法會返回滾動位置的對象信息,如果返回一個布爾假肢,或者是一個空的對象,那么不會發生滾動
//我們可以在該方法中設置返回值來指定頁面的滾動位置,例如:
return {x:0,y:0}
//表示在用戶切換路由時讓是所有頁面都返回到頂部位置
//如果返回savedPosition,那么在點擊后退按鈕時就會表現的像原生瀏覽器一樣,返回的頁面會滾動過到之前按鈕點擊跳轉的位置,大概寫法如下:
if(savedPosition){
return savedPosition
}else{
return {x:0,y:0}
}
//如果想要模擬滾動到錨點的行為:
if(to.hash){
return {
selector:to.hash
}
}
}
})
router-link屬性
-
to
表示目標路由的鏈接,當被點擊時,內部會立刻把to的值傳到router.push(),通過to傳遞的鏈接會被保存在history記錄中,所以可以使用瀏覽器回退
-
replace
如果設置replace屬性的話,當路由被點擊時,會調用router.replace(),本次操作不會留下history記錄
<router-link to="/home" replace></router-link>
-
append
在設置append屬性后,則表示正在當前相對路徑前添加路徑,例如我們是從/a導航到/b,那么在設置了append屬性后路由導航會跳轉到/a/b,而不是/b
<router-link to="a" append>a</router-link> //注意不要寫/a的形式
-
tag
如果想要把router-link渲染成除a外的其它標簽,可以使用tag來指定渲染之后應該是哪種標簽,同樣他還是會監聽點擊,觸發導航
<router-link to="/home" tag="li"></router-link>
-
exact
表示是否激活全局,可以理解為如果一個導航的路徑是/home開頭的,并且我們設置了點擊樣式,在/home路徑的導航設置了exact的情況下所有以、home開頭的路徑的導航的樣式都會同時改變
https://jsfiddle.net/8xrk1n9f/ 這是vue官方的一個簡單直觀的例子
-
將激活時的css類名應用在外層元素
有時候我們需要讓css類應用在外層元素,而不是a標簽本身,那么可以用router-link渲染外層元素,包裹著內層原生a標簽
<router-link tag="li" to="/home"> <a>Home</a> </router-link>
這種情況下,a將作為真實的鏈接,它會獲得正確的href,而激活時的css類名則會設置到外層的li
events
用來可以用來觸發導航的事件,默認是"click"
router-view屬性
- name
如果 <router-view>設置了名稱,則會渲染對應的路由配置中 components 下的相應組件