一文讓你徹底搞懂 vue-Router
路由是網路工程裡面的專業術語,就是通過互聯把資訊從源地址傳輸到目的地址的活動。本質上就是一種對應關係。分為前端路由和後端路由。
後端路由:
URL 的請求地址與伺服器上的資源對應,根據不同的請求地址返回不同的資源。
前端路由:
在單頁面應用中,根據用戶觸發的事件,改變URL在不刷新頁面的前提下,改變顯示內容。
1、前端路由實現原理
URL 的 hash 模式
改變 hash 值的時候,#是一個位置標識符,可以進行頁面內的位置跳轉,並不會刷新頁面。
通過 location.hash 改變頁面的 hash 值,如:
我們發現頁面並不會刷新。
URL 的 history 模式
history 模式,有 5 種改變 url 而不刷新頁面的方法,分別為:
history.pushState() //壓入棧
history.replaceState() // 替換當前url,不能返回上一個頁面
history.back() //返回上一個頁面
history.go(n) //n的值可以是大於0的,表示向前幾個,小於0時,表示向後退幾個
history.forward() //向前一步
history.go(-1) 等價於 history.back()
history.go(1) 等價於 history.forward()
前端三大框架,都有自己的路由:
Angular 有 ngRouter
React 有 ReactRouter
Vue 有 vue-Router
2、vue-Router 基本使用
2.1、安裝
npm install vue-router --save
使用 vue-router 的前提是 vue 必須使用
在 router 文件夾內 index.js 引入vue-router
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) //引用 vue-router 插件
2.2、配置路由
//配置路由與組件之間的關係 const route=[ { path: '/', // 當訪問 '/'的時候 路由重定向 到新的地址 '/home' redirect: '/home', }, { path: '/home', component: home, }, { path: '/login', component: login, }, ]
2.3、實例化
const router = new VueRouter({ mode: "history", //設置模式 routes });
2.4、掛載路由
到 main.js 中,vue 實例化中,把 router 掛載的 vue 上。
let app = new Vue({ el:'#app', data:{}, // 掛載到vue上面 router, })
2.5、頁面上添加 router-link 和 router-view
<!-- 添加路由 --> <router-link to="/home">首頁</router-link> <router-link to="/about">關於</router-link> <!-- 展示路由內容 --> <router-view />
router-link 默認會被渲染成 a 標籤,如:
<router-link to="/home">首頁</router-link> // 渲染成 <a href="#/home">首頁</a>
router-view 是用來佔位的,將路由對應的組件展示到該位置。
3、router 的模式
路由模式有兩種,hash 和 history 模式。
3.1、hash 模式
vue-router 默認使用的是 hash 模式。
hash 的 url 中錨點就是 #xx 號後的內容,通過錨點作為路由地址,我們通常改變的是#號後的內容,實現瀏覽器渲染指定的組件,錨點發生改變會觸發 onhashchange 事件。
3.2、history 模式
history就是正常的 url,沒有#號,使用的時候需要伺服器進行配置。history模式下,對應的方法與上述 5 個方法是一樣的。
vue-router 中可以指定需要的模式:
const router = new VueRouter({ mode:'history' })
4、router-link的屬性
router-link 默認會渲染成 a 標籤,但是有時候你想渲染成別的標籤也是可以的。
4.1、tag 屬性
tag屬性是用來設置 router-link 標籤渲染類型的,如我們想把 router-link 渲染成 button,如:
<router-link to="/home" tag="button">首頁</router-link>
查看渲染後的元素,發現變成 button 標籤了,對應的 to 添加的屬性值就會失效。此時點擊無法跳轉到對應內容,可繼續閱讀下邊跳轉方式。
除了 button ,tag 的屬性值還可以是其他任意標籤,router-link 自動渲染成對應的標籤。
4.2、replace 屬性
replace與上邊 history 模式中的 replaceState 對應,跳轉的時候不會留下 history 記錄,指定replace 的情況下,不能返回上一頁。
<router-link to="/home" replace>首頁</router-link>
4.3、active-class
active-class 設置 router-link 點擊當前選中的類名,默認情況下類名為:router-link-active
<a href="#/" aria-current="page" class="router-link-exact-active router-link-active"> 首頁 </a>
設置當前元素樣式需要設置到:router-link-active。
設置 active-class ,如:
<router-link to="/" active-class="active">首頁</router-link> // router-link-active 類名會被替換成 active
如果需要把全局的 router-link 的選擇類名都修改成自定義的,一個一個單獨設置工作量太大,可以在 router 中統一設置。
const router=new VueRouter({ routes, mode: 'hash', linkActiveClasss: 'active' //統一設置類名 })
5、vue-Rrouter 頁面跳轉方式
5.1、router-link 實現
// 簡單寫法 <router-link to="/">首頁</router-link> //使用動態的path <router-link :to="{ path : '/' }"></router-link> 可以使用path 也可以使用name //帶傳參跳轉1 <router-link :to=" { name:'home', params:{ id:'123' , name:'gq' }} "> </router-link> //帶傳參跳轉 <router-link :to=" { path:'/', query:{ id:'123' , name:'gq' }} "> </router-link>
5.2、通過 js 實現跳轉
// 簡單寫法 this.$router.push({ path:'/' }) // push 與history.pushState 一樣 //帶參跳轉 this.$router.push({ name: 'home' , params: { id:'123' , name:'gq' } }) //帶多種參數 this.$router.push({ name: 'home' , params: { id:'123' , name:'gq' }, query: { plan:'private' } })
6、動態路由
在某些情況下,一個頁面的 path 路徑可能是不確定的,如:希望的路徑為 /user/123或 /user/456 。後邊的值為用戶 id 或其他值。
配置路由
routers:[ { path: '/user/:id', component:()=>{ import('../views/user.vue') } } ]
添加路由
<router-link to="/user/123"> user:123 </router-link> <router-link to="/user/456"> user:456 </router-link> //動態設置後邊id值 <router-link :to=" '/user/'+id "> user:{{ id }} </router-link>
獲取後邊動態值
this.$route.params.id
此處的 id 是配置路由處設置的 id ,只要保持一致就可以了
方式二:使用 query 進行傳參
<router-link to="/user?id=123"></router-link>
//取值時
this.$route.query.id
另外,this.$router.addRoutes([]) 也可以添加動態路由,裡面傳的是一個數組,與 routes 配置一樣。
7、路由的懶載入
懶載入通俗的講就是使用的時候再載入,不使用的時候不載入。
打包構建應用程式的時候,js包會變得很大,影響載入速度,如果我們能把不同路由對應的組件分割成不同的程式碼塊,然後訪問路由的時候才載入對應的組件,這樣就更加高效了。
路由懶載入到底做了什麼呢?主要作用就是將路由對應的組件打包成一個js程式碼塊,只有路由訪問的時候,才載入對應的 js 。
//直接引用的 import Home from './component/home' const routes = [ { path:'/home', component:Home } ] //懶載入 const routes = [ { path:'/home', component:()=>{ import('./component/home') } } ]
8、嵌套路由
實際應用中,通常由多層嵌套的組件組合而成。
實現步驟:
第一:創建對應的子組件,並且在路由映射中配置對應的子路由。
第二:組件內部使用 router-view 標籤
{ path: "/body", component: ()=> import( "../components/bodyLayout.vue"),, children:[ { path: "manager", component: ()=> import( "../components/blankView.vue"), children:[ { path: "user", component: ()=> import( "../views/manager/user.vue") }, ] }, ] }
訪問 user 組件時,路由為:/body/manager/user
注意:嵌套路由設置 path 時,不能添加 「/」,否則路由就變了。
{ path: "/user", component: ()=> import( "../views/manager/user.vue") } //此時訪問路由就變成了 " /user "
9、router 與 route 區別
試著在main.js 列印 router 在任意組件內列印 this.$router,列印結果如圖:
我們發現兩個結果是一模一樣的。這樣我們就不難理解下面的意思了。
router 為 VueRouter 實例,擁有自己的方法,如:使用 new VueRouter創建的實例,想要導航到不同url,可以使用 router.push ,跳轉方式中有介紹。
route 為當前活躍狀態路由對象,有當前路由的資訊,可以通過該對象,獲取 path、params參數、query參數、name、matched、hash
10、路由守衛
為什麼使用導航守衛?我們來考慮一個需求:在 SPA應用中,網頁標題跟著頁面切換如何變動?
// 在對應的組件內添加 created(){ document.title="測試" } 訪問該組件時,標題自動切換為 」測試「
如果使用上述方法,那麼對應已開發的組件有多少個,我們就得添加多少次,實在是太麻煩了,所以我們要藉助路由守衛,統一修改,也便於維護。
10.1、全局守衛
1>、使用 router.beforeEach 註冊一個全局前置守衛,只要路由變動時,都會經過它。beforeEach 接收的參數是一個函數,包含的參數有三個。
router.beforeEach((to,from,next)=>{ // 路由從 from 跳轉到 to // 我們只需要在路由上增加一個 name屬性就可以了 document.title = from.name next() })
注意:上述三個參數順序不能改變。next 不能丟,必須添加,否則頁面跳轉的時候沒法到下一步,卡在空白區域。
2>、使用 router.afterEach 註冊一個全局後置守衛。
router.afterEach((to,from)=>{ console.log('後置守衛') })
這兩個守衛都是全局守衛,afterEach 是在路由跳轉完成才執行的,所以不需要 next 。參數只有兩個。
10.2、路由獨享守衛
路由配置上直接定義的守衛,用法與全局守衛一致,只是將其放在其中一個路由對象中,只有這個路由下起作用。
{ path: "/test", name: "測試", component: ()=> import( "../views/manager/test.vue"), beforeEnter:(to,from,next)=>{ console.log('test進入前') next() } }
這些守衛與全局前置守衛的方法參數是一樣的。
10.3、組件內守衛
可以在路由組件內直接定義路由導航守衛,定義在組件內的就是組件內守衛。
const Foo = { template: `...`, beforeRouteEnter(to, from, next) { // 在渲染該組件的對應路由被 confirm 前調用 // 不!能!獲取組件實例 `this` // 因為當守衛執行前,組件實例還沒被創建 }, beforeRouteUpdate(to, from, next) { // 在當前路由改變,但是該組件被複用時調用 // 舉例來說,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候, // 由於會渲染同樣的 Foo 組件,因此組件實例會被複用。而這個鉤子就會在這個情況下被調用。 // 可以訪問組件實例 `this` }, beforeRouteLeave(to, from, next) { // 導航離開該組件的對應路由時調用 // 可以訪問組件實例 `this` } }
注意:beforeRouteLeave 離開路由時執行,必須添加 next,否則無法正常跳轉到下一個路由。
11、keep-alive
切換路由的時候頁面每次都會重新渲染,我們有的組件會存在一些數據需要保留,不希望來回切換時每次都重新渲染,所以就使用 keep-alive 包裹組件,這樣只有第一次執行載入時會執行 created mounted 等鉤子函數。
keep-alive 是 Vue 內置的一個組件,可以使被包含的組件保留狀態,或避免重新渲染。
<div id="app"> <router-link to="/home">home</router-link> <router-link to="/login">login</router-link> <keep-alive> <router-view></router-view> </keep-alive> </div>
添加 keep-alive 組件,切換的時候,組件只會在第一次的時候渲染組件,之後進入不會重新渲染。
11.1、keep-alive 特定方法
activated(){ console.log('activated') }, deactivated(){ console.log("deactivated") }
這兩個函數,只有組件被保持了狀態,使用keep-alive時,才是有效會執行的。
keep-alive生命周期執行順序:
created -> mounted -> activated
deactivated 在退出後才會觸發
11.2、keep-alive 屬性
keep-alive 有兩個非常重要的屬性:
include – 字元串或正則表達式,只有匹配組件的時候才會被快取
exclude – 字元串或正則表達式,任何匹配的組件都不會被快取
<keep-alive include="test"> <router-view></router-view> </keep-alive> //test組件 添加name屬性 <template> <div> test </div> </template> <script> export default { name:'test' } <script>
此時只有 test 組件會被快取,其他任意組件都不會快取。
如果還有其他組件同時需要被快取,include可添加多個值,只用逗號隔開,但不能添加空格。
<keep-alive include="test,user"> <router-view></router-view> </keep-alive>
exclude的使用:
<keep-alive exclude="test,user"> <router-view></router-view> </keep-alive>
正好與上實例相反,只有 test,user 兩個組件不被快取,其他的被快取。