如今的前端框架都會配備一個路由框架,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>
vueRouter
會自動添加這個類,當點擊Home和Login來回切換時,發現html結構,a 標籤有一個樣式類 .router-link-active
也在來回切換, 原來這是當router-link 處於選中狀態時,所以咱們也能夠利用這個類來改變選中時的狀態,如選中時,讓它變成紅色,字體放大,若是未選中的也可在 router-link
直接給它添加一個 class
就能夠了,好比自定義一個default-styles
html
屬性有 to 、replace、 append、 tag、 active-class、 exact 、 event、 exact-active-class
前端
//字符串形式 <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>
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
,看下方圖片渲染結果:vue
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: "用戶" } } ] })
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
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
click
<router-link to="/article" event="mouseover">article</router-link>
若是咱們不加event
,那麼默認狀況下是當咱們點擊article
的時候,跳轉到相應的頁面,但當咱們加上event
的時候,就能夠改變觸發導航的事件,好比鼠標移入事件web
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)
boolean
默認值: false
設置 append 屬性後,則在當前 (相對) 路徑前添加基路徑vue-router
<router-link to="a" append>Home</router-link>
設置append屬性後,則在當前路徑前添加基路徑,例如,咱們從/a導航到一個相對路徑b,若是沒有配置append,則路徑爲/b,若是配了,則爲/a/b
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包
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,用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採用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>
一、全局守衛
二、路由獨享守衛
三、路由組件內的守衛
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') })
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,執行順序大概是這樣的
當我點擊User
時回調用路由組件內守衛的beforeRouteEnter
,而後當我點擊About
時,會調用beforeRouteLeave
也能夠先獲取數據,等數據獲取出來才真正的顯示頁面。
須要注意:這裏是拿不到組件this,由於沒有經過next以前,組件沒有被建立,因此用this === undefined
,不能調用上的任何東西
對於user/123,切到user/456 這樣的路由頁面,通常在mounted獲取數據,第二次進來的時候,不會被觸發(數據不會更新),因此數據的初始化獲取不要用mounted,最好使用beforeRouteUpdate
,或者使用watch,watch相對比較麻煩,並且不能控制路由跳轉的行爲
beforeRouteLeave:能夠用來表單填寫成功,是否保存提示等
const router = new VueRouter({ mode: 'history', routes: [ { path: '/user', component: User, beforeEnter: function guardRoute(to, from, next) { // 參數用法什麼的都同樣,調用順序在全局前置守衛後面,因此不會被全局守衛覆蓋 console.log('導航路由獨享守衛:beforeEnter') next() } } ] })
好比從User
組件跳轉到About
組件所執行的順序
一、beforeRouteLeave //路由組件內守衛
二、beforeEach // 全局前置守衛-路由進入開始
三、beforeEnter // 導航路由獨享守衛
四、beforeRouteEnter // 路由組件內前置守衛
五、beforeResolve //全局解析守衛
六、afterEach // 全局後置鉤子