路由中有三個基本的概念 route, routes, router
1,
route
,它是一條路由,由這個英文單詞也可以看出來,它是單數, Home按鈕 => home內容, 這是一條route, about按鈕 => about 內容, 這是另一條路由。
2,
routes
是一組路由,把上面的每一條路由組合起來,形成一個數組。[{home 按鈕 =>home內容 }, { about按鈕 => about 內容}]
3,
router
是一個機制,相當于一個管理者,它來管理路由。因為routes 只是定義了一組路由,它放在哪里是靜止的,當真正來了請求,怎么辦? 就是當用戶點擊home 按鈕的時候,怎么辦?這時router 就起作用了,它到routes 中去查找,去找到對應的 home 內容,所以頁面中就顯示了 home 內容。
4,客戶端中的路由,實際上就是dom 元素的顯示和隱藏。當頁面中顯示home 內容的時候,about 中的內容全部隱藏,反之也是一樣??蛻舳寺酚捎袃煞N實現方式:基于hash 和基于html5 history api.
vue-router中的路由也是基于上面的內容來實現的
在vue中實現路由還是相對簡單的。因為我們頁面中所有內容都是組件化的,我們只要把路徑和組件對應起來就可以了,然后在頁面中把組件渲染出來。
1, 頁面實現(html模版中)
在vue-router中, 我們看到它定義了兩個標簽
<router-link> 和<router-view>
來對應點擊和顯示部分。<router-link>
就是定義頁面中點擊的部分,<router-view>
定義顯示部分,就是點擊后,區配的內容顯示在什么地方。所以<router-link>
還有一個非常重要的屬性to
,定義點擊之后,要到哪里去, 如:<router-link to="/home">Home</router-link>
2, js 中配置路由
首先要定義route, 一條路由的實現。它是一個對象,由兩個部分組成:
path
和component
。 path 指路徑,component 指的是組件。如:{path:’/home’, component: home}
我們這里有兩條路由,組成一個routes:
const routes = [
{ path: '/home', component: Home },
{ path: '/about', component: About }
]
最后創建router實例
對路由進行管理,它是由構造函數 new vueRouter()
創建,接受routes 參數
const router = new VueRouter({
routes // routes: routes 的簡寫
})
配置完成后,把router
實例注入到 vue 根實例中,就可以使用路由了
const app = new Vue({
router
}).$mount('#app')
執行過程:當用戶點擊router-link
標簽時,會去尋找它的 to
屬性, 它的 to 屬性和 js 中配置的路徑{ path: '/home', component: Home}
path 一一對應,從而找到了匹配的組件, 最后把組件渲染到 <router-view>
標簽所在的地方。所有的這些實現才是基于hash 實現的。
動態路由
上面我們定義的路由,都是嚴格匹配的,只有
router-link
中的to
屬性和 js 中一條路由route中 path
一模一樣,才能顯示相應的組件component
. 但有時現實卻不是這樣的,當我們去訪問網站并登錄成功后,它會顯示歡迎你,+ 你的名字
。不同的用戶登錄, 只是顯示“你的名字” 部分不同,其它部分是一樣的。
這就表示,它是一個組件,假設是
user組件
。不同的用戶(就是用戶的id不同),它都會導航到同一個user 組件
中。這樣我們在配置路由的時候,就不能寫死, 就是路由中的path
屬性,不能寫死,那要怎么設置? 導航到user 組件
,路徑中肯定有user, id 不同,那就給路徑一個動態部分來匹配不同的id.
在
vue-router
中,動態部分 以 : 開頭,那么路徑就變成了/user/:id
, 這條路由就可以這么寫:{ path:"/user/:id", component: user }
.
我們定義一個
user組件
(自己隨便寫一個就好了),頁面中再添加兩個router-link
用于導航, 最后router.js中添加路由配置,來體驗一下
app.vue 中添加兩個router-link:
<template>
<div id="app">
<img src="./assets/logo.png">
<header>
<router-link to="/home">Home</router-link>
<router-link to="/about">About</router-link>
<!-- 增加兩個到user組件的導航,可以看到這里使用了不同的to屬性 -->
<router-link to="/user/123">User123</router-link>
<router-link to="/user/456">User456</router-link>
</header>
<router-view></router-view>
</div>
</template>
index.js 配置user動態路由:
const routes = [
{
path:"/home",
component: home
},
{
path: "/about",
component: about
},
/*新增user路徑,配置了動態的id*/
{
path: "/user/:id",
component: user
},
{
path: '/',
redirect: '/home'
}
]
user組件
<template>
<div>
<h1>User</h1>
<div>我是user組件</div>
</div>
</template>
<script>
export default {
}
</script>
這時在頁面中點擊user123 和user456, 可以看到它們都導航到user組件,配置正確。
在動態路由中,怎么獲取到動態部分? 因為在組件中是可以顯示不同部分的,就是上面提到的“你的名字”。其實,當整個
vue-router
注入到根實例后,在組件的內部,可以通過this.$route
來獲取到 router 實例。
//動態路由匹配
path:'/user/:id'
this.$route.params.id
它有一個
params
屬性,就是來獲得這個動態部分的。它是一個對象,屬性名,就是路徑中定義的動態部分 id, 屬性值就是router-link中to 屬性
中的動態部分,如123。使用vuex時,組件中想要獲取到state 中的狀態,是用computed 屬性,在這里也是一樣,在組件中,定義一個computed 屬性**dynamicSegment**
, user 組件修改如下:
<template>
<div>
<h1>User</h1>
<div>我是user組件, 動態部分是{{dynamicSegment}}</div>
</div>
</template>
<script>
export default {
computed: {
dynamicSegment () {
return this.$route.params.id
}
}
}
</script>
這里還有最后一個問題,就是動態路由在來回切換時,由于它們都是指向同一組件,vue不會銷毀再創建這個組件,而是復用這個組件,就是當第一次點擊(如:user123)的時候,vue 把對應的組件渲染出來,但在user123, user456點擊來回切換的時候,這個組件就不會發生變化了,組件的生命周期不管用了。
這時如果想要在組件來回切換的時候做點事情,那么只能在組件內部(user.vue中)利用watch
來監聽$route
的變化。把上面的代碼用監聽$route
實現
<script>
export default {
data () {
return {
dynamicSegment: ''
}
},
watch: {
$route (to,from){
// to表示的是你要去的那個組件,from 表示的是你從哪個組件過來的,它們是兩個對象,你可以把它打印出來,它們也有一個param 屬性
console.log(to);
console.log(from);
this.dynamicSegment = to.params.id
}
}
}
</script>
tips:
this.$route
和this.$router
區別
this.$router
是指整個大的路由實例對象
this.$route
是當前路由相關的參數信息(想打印地址欄相關信息)
嵌套路由
嵌套路由,主要是由我們的頁面結構所決定的。當我們進入到
home頁面
的時候,它下面還有分類,如手機系列,平板系列,電腦系列。當我們點擊各個分類的時候,它還是需要路由到各個部分,如點擊手機,它肯定到對應到手機的部分。
在路由的設計上,首先進入到 home ,然后才能進入到phone, tablet, computer. Phone, tablet, compute 就相當于進入到了home的子元素。所以vue 提供了childrens 屬性,它也是一組路由,相當于我們所寫的routes。
首先,在home頁面上定義三個
router-link
標簽用于導航,然后再定義一個router-view
標簽,用于渲染對應的組件。router-link 和router-view
標簽要一一對應。home.vue 組件修改如下:
<template>
<div>
<h1>home</h1>
<!-- router-link 的to屬性要注意,路由是先進入到home,然后才進入相應的子路由如 phone,所以書寫時要把 home 帶上 -->
<p>
<router-link to="/home/phone">手機</router-link>
<router-link to="/home/tablet">平板</router-link>
<router-link to="/home/computer">電腦</router-link>
</p>
<router-view></router-view>
</div>
</template>
index.js 配置路由,修改如下:
const routes = [
{
path:"/home",
// 下面這個屬性也不少,因為,我們是先進入home頁面,才能進入子路由
component: home,
// 子路由
children: [
{
path: "phone",
component: phone
},
{
path: "tablet",
component: tablet
},
{
path: "computer",
component: computer
}
]
},
{
path: "/about",
component: about
},
{
path: "/user/:id",
component: user
},
{
path: '/',
redirect: '/home'
}
]
這時當我們點擊home 時,它下面出現手機等字樣,但沒有任何對應的組件進行顯示,這通常不是我們想要的。要想點擊home時,要想渲染相對應的子組件,那還需要配置一條路由。當進入到home 時,它在children中對應的路由path 是空 ‘’,完整的childrens 如下:
children: [
{
path: "phone",
component: phone
},
{
path: "tablet",
component: tablet
},
{
path: "computer",
component: computer
},
// 當進入到home時,下面的組件顯示
{
path: "",
component: phone
}
]
命名路由
命名路由,很簡單,因為根據名字就可以知道,這個路由有一個名字,那就直接給這個路由加一個name
屬性,就可以了。 給user 路由加一個name 屬性:
{
path: "/user/:id",
name: "user",
component: user
}
命名路由的使用, 在router-link 中to
屬性就可以使用對象了
//和下面等價
<router-link to="/user/123">User123</router-link>
// 當使用對象作為路由的時候,to前面要加一個冒號,表示綁定
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
編程式導航:這主要應用到按鈕點擊上。當點擊按鈕的時候,跳轉另一個組件, 這只能用代碼,調用rourter.push()
方法。 當們把router 注入到根實例中后,組件中通過this.$router
可以獲取到router, 所以在組件中使用
this.$router.push("home") //就可以跳轉到home界面
路由鉤子(路由守衛)
在某些情況下,當路由跳轉前或跳轉后、進入、離開某一個路由前、后,需要做某些操作,就可以使用路由鉤子來監聽路由的變化
vue路由鉤子大致可以分為三類:
1、全局鉤子
2、單個路由的鉤子
3、組件內鉤子
第一種 全局鉤子函數
主要包括beforeEach和aftrEach
beforeEach函數有三個參數:
to:router即將進入的路由對象
from:當前導航即將離開的路由
next:Function,進行管道中的一個鉤子,如果執行完了,則導航的狀態就是 confirmed (確認的);否則為false,終止導航。
afterEach函數不用傳next()函數
這類鉤子主要作用于全局,一般用來判斷權限,以及以及頁面丟失時候需要執行的操作
使用 router.beforeEach 注冊一個全局的 before 鉤子
var routes = [{
path:'/route1',
name:'route1',
component:() = > import('./index.vue') //調用的時候再開始加載
}]
const router = new VueRouter({
routes;
})
//開始注冊
router.beforeEach((to, from, next) => {
console.log('beforeEach')
//next() //如果要跳轉的話,一定要寫上next()
//next(false) //取消了導航
next() //正常跳轉,不寫的話,不會跳轉
})
router.afterEach((to, from) => { // 舉例: 通過跳轉后改變document.title
if( to.meta.title ){
window.document.title = to.meta.title //每個路由下title
}else{
window.document.title = '默認的title'
}
})
第二種 針對單個路有鉤子函數
主要用于寫某個指定路由跳轉時需要執行的邏輯,只有
beforeEnter
,在進入前執行,to參數就是當前路由
routes: [
{
path: '/home',
component:() = > import('./home.vue') //調用的時候再開始加載
beforeEnter: (to, from, next) => {
// ...
next() //正常跳轉,不寫的話,不會跳轉
}
}
]
第三種 組件級鉤子函數
主要包括
beforeRouteEnter和beforeRouteUpdate ,beforeRouteLeave
,這幾個鉤子都是寫在組件里面也可以傳三個參數(to,from,next)
,作用與前面類似
1 beforeRouteEnter
在導航確認之前調用,新組件的 beforeCreate 之前調用,所以特別注意它的 this 是 undefined,不過,可以通過傳一個回調給 next來訪問組件實例
2 beforeRouteUpdate
用法:點擊更新二級導航時調用。
3 beforeRouteLeave
離開當前界面之前調用,用法:1. 需要的保存或者刪除的數據沒有完成當前操作等等原因,禁止界面跳轉。
組件鉤子用法和data,methods平級
data:{},
methods: {}
beforeRouteEnter(to, from, next){ // 這個路由鉤子函數比生命周期beforeCreate函數先執行,所以this實例還沒有創建出來
console.log("beforeRouteEnter")
console.log(this) //這時this還是undefinde,因為這個時候this實例還沒有創建出來
next((vm) => { //vm,可以這個vm這個參數來獲取this實例,接著就可以做修改了
vm.text = '改變了'
})
},
beforeRouteUpdate(to, from, next){//可以解決二級導航時,頁面只渲染一次的問題,也就是導航是否更新了,是否需要更新
console.log('beforeRouteUpdate')
next();
},
beforeRouteLeave(to, from, next){// 當離開組件時,是否允許離開
next()
}
轉載整理https://blog.csdn.net/weixin_41910848/article/details/81697577