關於vue-router可能須要注意到的事項

如今的前端框架都會配備一個路由框架,vue有vue-router,react有react-router,angular也有angular-route,固然還有一些優秀插件來完善這些router的作更多的事情

安裝

npm i vue-router -S

基本使用

import Vue from './view-global';
import VueRouter from 'vue-router'
import App from './micro/app.vue'

import Home from './micro/home'
import Login from './micro/login'
import About from './micro/about'
import User from './micro/user'
const router = new VueRouter({
    mode: 'hash',
    routes: [
        { path: '/home', name: 'Home', component: Home, meta: { title: "主頁" } },
        { path: '/login', name: 'Login', component: Login, meta: { title: "登陸" } },
        { path: '/about', name: 'About', component: About, meta: { title: "關於" } },
        { path: '/user', name: 'User', component: User, meta: { title: "用戶" } }
    ]
})
Vue.use(VueRouter)
new Vue({
    router,
    render: h => h(App),
}).$mount('#app')
// app.vue
<template>
    <div>
        <router-link to="/home" class="default-styles"> Home </router-link><br>
        <router-link to="/login" class="default-styles">Login</router-link><br>
        <router-link :to="{ path: '/about' }" class="default-styles">About</router-link><br>
        <router-link :to="{ name: 'User'}" class="default-styles">User</router-link>
        <router-view/>
    </div>
</template>
<style lang="less" scoped>
.default-styles{
    color: gray;
    font-size: 14px;
}
.router-link-active{
    color: red;
    font-size: 26px;
}
</style>

router-link-active

vueRouter 會自動添加這個類,當點擊Home和Login來回切換時,發現html結構,a 標籤有一個樣式類 .router-link-active 也在來回切換, 原來這是當router-link 處於選中狀態時,所以咱們也能夠利用這個類來改變選中時的狀態,如選中時,讓它變成紅色,字體放大,若是未選中的也可在 router-link 直接給它添加一個 class就能夠了,好比自定義一個default-styleshtml

router-link

屬性有 to 、replace、 append、 tag、 active-class、 exact 、 event、 exact-active-class前端

to(必選參數):類型string/location
//字符串形式
<router-link to="/home">Home</router-link>
//動態綁定 v-bind
<router-link :to="'/home'">Home</router-link>
<router-link :to="{ path: '/home' }">Home</router-link>
<router-link :to="{ name: 'User'}">User</router-link>
// 帶參數 參數在url 獲取參數 this.$route.query
<router-link :to="{ name: 'User', query: {color: 'red' }}">query帶參數</router-link>
// 帶參數 獲取參數 this.$route.params
<router-link :to="{ name: 'User', params: { color: 'red' }}">params帶參數</router-link><br>
tag 類型string,默認值a
// 若是想要 <router-link> 渲染成某種標籤,例如 <li>
<router-link :to="'/home'" tag="li">Home</router-link>
// 若是此時咱們想要在這個li標籤中添加a標籤,以下所示,能夠不爲a標籤添加href屬性便可哦
<router-link :to="{ name: 'User', params: { color: 'red' }}" tag="li">
    <a>User</a>
</router-link>

能夠看渲染結果,在這種狀況下,<a> 將做爲真實的連接 (它會得到正確的 href 的),而 "激活時的CSS類名" 則設置到外層的 li,看下方圖片渲染結果:
image.pngvue

active-class : 類型 string默認值:router-link-active
// 修改激活選中的class類名
<router-link :to="{ name: 'User', query: {color: 'red' }}" active-class="activeClass">帶參數</router-link>
// 全局修改
const router = new VueRouter({
    mode: 'hash',
    linkActiveClass: 'activeClass', // 全局配置
    routes: [
        { path: '/home', name: 'Home', component: Home, meta: { title: "主頁" } },
        { path: '/login', name: 'Login', component: Login, meta: { title: "登陸" } },
        { path: '/about', name: 'About', component: About, meta: { title: "關於" } },
        { path: '/user', name: 'User', component: User, meta: { title: "用戶" } }
    ]
})

image.png

exact-active-class 類型 string 默認值:router-link-exact-active

配置當連接被精確匹配的時候應該激活的 class。注意默認值也是能夠經過路由構造函數選項 linkExactActiveClass 進行全局配置的,看起來有點模糊,舉個栗子,例如:react

<router-link to="/article" active-class="router-active"></router-link>
// 當用戶訪問 /article/1 時會被激活爲
<a href="#/article" class="router-active"></a>

// 修改一下

<router-link to="/article" exact-active-class="router-active"></router-link>
// 當用戶訪問 /article/1 時會被激活爲,不會激活這個link的class
<a href="#/article"></a>

router-link 默認狀況下的路由是模糊匹配webpack

exact 類型 boolean 默認值:false

"是否激活" 默認類名的依據是 inclusive match (全包含匹配), 舉個例子git

<li><router-link to="/">全局匹配</router-link></li>
 <li><router-link to="/" exact>exact嚴格匹配</router-link></li>

簡單點說,第一個的話,若是地址是/a,或/a/b,……都會匹配成功,
但加上exact,只有當地址是/時被匹配,其餘都不會匹配成功github

event 類型: string | Array<string> 默認值: click
<router-link to="/article" event="mouseover">article</router-link>

若是咱們不加event,那麼默認狀況下是當咱們點擊article的時候,跳轉到相應的頁面,但當咱們加上event的時候,就能夠改變觸發導航的事件,好比鼠標移入事件web

replace 類型: boolean 默認值: false

設置 replace 屬性的話,當點擊時,會調用 router.replace() 而不是 router.push(),因而導航後不會留下 history 記錄
push replace go 之間的區別ajax

router.push() :導航跑到不一樣的URL,這個方法會向history棧添加一個新的記錄,因此,當用戶點擊瀏覽器後退按鈕時,則回到以前的url
router.replace(): 跟router.push做用是同樣的,可是,它不會向history添加新記錄,而是跟它的方法名同樣替換掉當前的history記錄
router.go(n): 這個方法的參數是一個整數,意思是在history記錄中向前或者後退多少步,相似window.history.Go(n)
append 類型: boolean 默認值: false

設置 append 屬性後,則在當前 (相對) 路徑前添加基路徑vue-router

<router-link to="a" append>Home</router-link>

設置append屬性後,則在當前路徑前添加基路徑,例如,咱們從/a導航到一個相對路徑b,若是沒有配置append,則路徑爲/b,若是配了,則爲/a/b

快速設置title

Router.beforeEach((to,from,next) => {
    window.document.title= to.meta.title
})

滾動行爲

使用前端路由,當切換到新路由時,想要頁面滾到頂部,或者是保持原先的滾動位置,就像從新加載頁面那樣。 vue-router 能作到,並且更好,它讓你能夠自定義路由切換時頁面如何滾動

// 2.8.0 新增
const router = new VueRouter({
    scrollBehavior (to, from, savedPosition) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve({ x: 0, y: 0 })
            }, 500)
        })
    }        
})

利用路由元信息更細顆粒度地控制滾動,能夠查看github官方列子

路由懶加載

官方描述:當打包構建應用時,JavaScript 包會變得很是大,影響頁面加載。若是咱們能把不一樣路由對應的組件分割成不一樣的代碼塊,而後當路由被訪問的時候才加載對應組件,這樣就更加高效了

加載方式

非按需加載
{ path: '/user', name: 'User', component:require(['./micro/user'], resolve), meta: { title: "用戶" } }
按需加載
{ path: '/user', name: 'User', component: (resolve) => require(['./micro/user'], resolve), meta: { title: "用戶" } }
// 或者使用webpack的require.ensure技術
{ path: '/user', name: 'User', component: resolve => require.ensure([], () => resolve(require('./micro/user')), 'user'), meta: { title: "用戶" } }

按需加載會在頁面第一次請求的時候,把相關路由組件塊的js添加上;非按需加載則會把全部的路由組件塊的js包打在一塊兒。
當業務包很大的時候建議用路由的按需加載(懶加載),能夠看我網站,打開控制檯,當點擊左側菜單,會發現加載相對應的js包

image.png

require.ensure 參數解釋
第一個參數的依賴關係是一個數組,表明了當前須要進來的模塊的一些依賴
第二個參數回調就是一個回調函數其中須要注意的是,這個回調函數有一個參數要求,經過這個要求就能夠在回調函數內動態引入其餘模塊值得注意的是,雖然這個要求是回調函數的參數,理論上能夠換其餘名稱,可是其實是不能換的,不然的的的的WebPack就沒法靜態分析的時候處理它
第三個參數errorCallback比較好理解,就是處理錯誤的回調
第四個參數chunkName則是指定打包的組塊名稱

異步組件

// setTimeout 演示ajax
const User= Vue.component('later', function (resolve) {
    setTimeout(function () {
        require(['./user.vue'], resolve)
    }, 3000);
});
components: {
   User
},

注意異步組件頁面渲染的時候會跳動,使用下方高級異步組件,解決體驗問題

// 更高級的異步組件
const AsyncComponent = () => ({
  // 須要加載的組件 (應該是一個 `Promise` 對象)
  component: import('./MyComponent.vue'),
  // 異步組件加載時使用的組件
  loading: LoadingComponent,
  // 加載失敗時使用的組件
  error: ErrorComponent,
  // 展現加載時組件的延時時間。默認值是 200 (毫秒)
  delay: 200,
  // 若是提供了超時時間且組件加載也超時了,
  // 則使用加載失敗時使用的組件。默認值是:`Infinity`
  timeout: 3000
})

hash模式和history模式

hash模式:

在瀏覽器中符號「#」,#以及#後面的字符稱之爲hash,用window.location.hash讀取; 特色:hash雖然在URL中,但不被包括在HTTP請求中;用來指導瀏覽器動做,對服務端安全無用,hash不會重加載頁面。 hash 模式下,僅 hash 符號以前的內容會被包含在請求中,如 https://www.vipbic.com,所以對於後端來講,即便沒有作到對路由的全覆蓋,也不會返回 404 錯誤

簡單實現hash

<div id="app">
    <a class="hash a">#a.html</a>
    <a class="hash b">#b.html</a>
</div>
<script>
    // 再點擊時注意觀看瀏覽器地址欄
    document.querySelectorAll('.hash').forEach( function(item, index) {
      item.addEventListener('click',(e)=>{
        e.preventDefault()
        var link = item.textContent;
        location.hash=  link;
      },false)
    });
    //每點一下都會觸發-hashchange
    window.addEventListener('hashchange', (e)=>{
      console.log({
        location: location.href,
        state: location.hash,
        e:e
      })
    });
</script>

history模式:

history採用HTML5的新特性;且提供了兩個新方法:pushState(),replaceState()能夠對瀏覽器歷史記錄棧進行修改,以及popState事件的監聽到狀態變動。 history 模式下,前端的 URL 必須和實際向後端發起請求的 URL 一致,如 http://www.xxx.com/items/id。後端若是缺乏對 /items/id 的路由處理,將返回 404 錯誤。Vue-Router 官網裏如此描述:「不過這種模式要玩好,還須要後臺配置支持……因此呢,你要在服務端增長一個覆蓋全部狀況的候選資源:若是 URL 匹配不到任何靜態資源,則應該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面。

簡單實現history

<div id="app">
    <a class="api a">a.html</a>
    <a class="api b">b.html</a>
</div>
<script>
// 再點擊時注意觀看瀏覽器地址欄
document.querySelectorAll('.api').forEach( function(item, index) {
    item.addEventListener('click',(e)=>{
        e.preventDefault()
        var link = item.textContent;
        window.history.pushState({name:'api'},link,link);
      },false)
    });
    // 下面說一下replaceState,其實跟pushState差很少,只是replaceState()修改當前歷史記錄條目,而不是建立一個新的。
    // 在點擊瀏覽器的後腿前進按鈕時會觸發-popstate 
    window.addEventListener('popstate', (e)=>{
      console.log({
        location: location.href,
        state: e.state,
        e:e
      })
});
</script>

vue-router導航守衛的類型

一、全局守衛
二、路由獨享守衛
三、路由組件內的守衛

全局守衛

vue-router全局有三個守衛
router.beforeEach 全局前置守衛 進入路由以前
router.beforeResolve 全局解析守衛(2.5.0+) 在beforeRouteEnter調用以後調用
router.afterEach 全局後置鉤子 進入路由以後
全局導航守衛的執行順序

例如從 /Home 頁面跳轉到 /User,全局導航守衛執行順序大概是這樣的

router.beforeEach((to, from, next) => {
    console.log('全局前置守衛: beforeEach')
    next()
})
router.beforeResolve((to, from, next) => {
    console.log('全局解析守衛: beforeResolve')
    next()
})
router.afterEach((to, from) => {
    console.log('全局後置鉤子: afterEach')
})

image.png

路由組件內守衛

beforeRouteEnter 進入路由前, 在路由獨享守衛後調用 不能 獲取組件實例 this,組件實例還沒被建立
beforeRouteUpdate (2.2) 路由複用同一個組件時, 在當前路由改變,可是該組件被複用時調用 能夠訪問組件實例 this
beforeRouteLeave 離開當前路由時, 導航離開該組件的對應路由時調用,能夠訪問組件實例 this
beforeRouteEnter(to, from, next) {
    console.log('進入前:beforeRouteEnter')
    next()
},
beforeRouteUpdate(to, from, next) {
    console.log('路由改變時:beforeRouteUpdate') // 好比user/123,切到user/456,纔會觸發
    next()
},
beforeRouteLeave(to, from, next) {
    console.log('離開前:beforeRouteLeave')
    next()
}
路由組件內守衛的執行順序

例如從 /Home 頁面跳轉到 /User 而後在跳到Home,執行順序大概是這樣的

image.png

當我點擊User時回調用路由組件內守衛的beforeRouteEnter,而後當我點擊About時,會調用beforeRouteLeave

beforeRouteEnter

也能夠先獲取數據,等數據獲取出來才真正的顯示頁面。
須要注意:這裏是拿不到組件this,由於沒有經過next以前,組件沒有被建立,因此用this === undefined ,不能調用上的任何東西

beforeRouteUpdate注意點

對於user/123,切到user/456 這樣的路由頁面,通常在mounted獲取數據,第二次進來的時候,不會被觸發(數據不會更新),因此數據的初始化獲取不要用mounted,最好使用beforeRouteUpdate,或者使用watch,watch相對比較麻煩,並且不能控制路由跳轉的行爲

beforeRouteLeave

beforeRouteLeave:能夠用來表單填寫成功,是否保存提示等

導航路由獨享守衛

const router = new VueRouter({
    mode: 'history',
    routes: [
      {
        path: '/user',
        component: User,
        beforeEnter: function guardRoute(to, from, next) {
    // 參數用法什麼的都同樣,調用順序在全局前置守衛後面,因此不會被全局守衛覆蓋
          console.log('導航路由獨享守衛:beforeEnter')
          next()
        }
      }
    ]
})

總結路由執行順序

好比從User組件跳轉到About組件所執行的順序

image.png

一、beforeRouteLeave //路由組件內守衛
二、beforeEach // 全局前置守衛-路由進入開始
三、beforeEnter // 導航路由獨享守衛
四、beforeRouteEnter // 路由組件內前置守衛
五、beforeResolve //全局解析守衛
六、afterEach // 全局後置鉤子

更多關於vue-route

動態組件 & 異步組件
滾動行爲
導航守衛實踐與解析

關於我

https://www.vipbic.com/.png

相關文章
相關標籤/搜索