關於標題,應該算不上是標題黨,由於內容真的不少很長很全面.主要是在官網的基礎上又詳細總結,舉例了不少東西.確保全部新人都能理解!因此實際上不少東西是比官網還詳細的.你想要的,在官網上沒理解的,基本在這裏都能找到解答!原本想分紅兩篇發的,但想一想男人長點也沒什麼很差的.因此也但願各位收藏插眼標記(滑稽)html
特色:本文主要是參考了官方文檔.除了不經常使用的過渡動效和數據獲取,都進行了分析說明.說明:每一節都在文檔的基礎上進行了更通俗的解釋;例子:每一節都添加了單獨的例子進行詳細的說明,官方沒有或複雜或略過的都有詳細的說明.總結:每一節都會有tips注意點,實際開發的經驗和總結.前端
使用方法:vue
若是是新手,就從頭開始看,前5章的內容都是逐步讓你熟悉VueRouter,而且第5章也給出了本地實際搭建的代碼示例.react
若是你對VueRouter有了必定了解,則能夠根據目錄,自行選擇查看.或者全局搜索關鍵字快速定位.webpack
吐槽:如今關於VueRouter相關能搜到的大部分都是copy徹底摘抄官方文檔拼湊的文章.很反感這樣的文章!基本沒什麼養分!你在官網上不明白的在他那裏基本也看不明白.web
vue-router和vue.js是深度集成的,適合用於單頁面應用.傳統的路由是用一些超連接來實現頁面切換和跳轉.而vue-router在單頁面應用中,則是組件之間的切換.其本質就是:創建並管理url和對應組件之間的映射關係.
vue-router
這裏簡單先以官網的例子,瞭解vue-router有哪幾大部分組成,對vue-router有一個初步印象.npm
首先是html部分.這裏主要是兩個做用:編程
1,router-link組件來導航,用戶點擊後切換到相關視圖.segmentfault
2,router-view組件來設置切換的視圖在哪裏渲染.(一個頁面也能夠有多個router-view分別展現特定的視圖,而且支持嵌套)
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 組件來導航. -->
<!-- 經過傳入 `to` 屬性指定連接. -->
<!-- <router-link> 默認會被渲染成一個 `<a>` 標籤 -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的組件將渲染在這裏 -->
<router-view></router-view>
</div>
複製代碼
這裏實際項目寫法代碼能夠參考我後面的第5章.下面我就簡單總結下大概分那幾步:
// 0\. 若是使用模塊化機制編程,導入Vue和VueRouter,要調用 Vue.use(VueRouter)
// 1\. 定義 (路由) 組件。
// 能夠從其餘文件 import 進來
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
// 2\. 定義路由
// 每一個路由應該映射一個組件。 其中"component" 能夠是
// 經過 Vue.extend() 建立的組件構造器,
// 或者,只是一個組件配置對象。
// 咱們晚點再討論嵌套路由。
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
// 3\. 建立 router 實例,而後傳 `routes` 配置
// 你還能夠傳別的配置參數, 不過先這麼簡單着吧。
const router = new VueRouter({
routes // (縮寫) 至關於 routes: routes
})
// 4\. 建立和掛載根實例。
// 記得要經過 router 配置參數注入路由,
// 從而讓整個應用都有路由功能
const app = new Vue({
router
}).$mount('#app')
// 如今,應用已經啓動了!
複製代碼
經過注入路由器,咱們能夠在任何組件內經過 this.$router
訪問路由器,也能夠經過 this.$route
訪問當前路由對象:
Tips:這裏我簡單說明下$router
和$route
的區別:
$router
是指整個路由實例,你能夠操控整個路由,經過'$router.push'往其中添加任意的路由對象.$route
:是指當前路由實例('$router')跳轉到的路由對象;// Home.vue
export default {
computed: {
username () {
// 咱們很快就會看到 `params` 是什麼
return this.$route.params.username
}
},
methods: {
goBack () {
window.history.length > 1
? this.$router.go(-1)
: this.$router.push('/')
}
}
}
複製代碼
圖片中router.js就是路由實例配置文件
PS: 這裏圖說的有點不許確,to並非僅僅對應path值.要分具體狀況, 詳情查看官方to的api.學習一個新知識,只看而後想一想.嗯,大概是這樣的.這樣是沒有任何效果的.沒有實際敲過,使用過,都算不上是你的知識.因此,強烈建議你們邊看邊敲邊思考總結. 這裏提供兩種方式:
這兩種方式都很好.我的建議有條件的選第二種,更加直觀,更加貼近本身的實際項目需求.
學習配置vue-router,必定要考慮兩個層面:
<router-link>
和<router-view>
npm i vue-router -s
複製代碼
<!--這裏引用官方例子的寫法-->
<div id='app'>
<p>
<router-link to="/user/foo">/user/foo</router-link>
<router-link to="/user/bar">/user/bar</router-link>
</p>
<router-view>PS:寫在這裏,即router-view裏的內容是不會顯示在頁面上的!</router-view>
</div>
複製代碼
關於to
的更詳細用法: 能夠參考官方的api文檔.用法很簡單這裏我就不重複了.
//第一步:引入必要的文件
import Vue from 'vue';//加載全局組件時,都須要引入Vue
import Router from 'vue-router';//引入vue-router
//引入在路由中須要用到的組件
import User from '@/components/user/User' //這裏省略了.vue
...
//第二步:加載Router
Vue.use(Router);//加載全局組件Router
//第三步:配置路由實例
export default new Router({
//mode:'history', //路由模式:默認爲hash,若是改成history,則須要後端進行配合
//base:'/',//基路徑:默認值爲'/'.若是整個單頁應用在/app/下,base就應該設爲'/app/'.通常能夠寫成__dirname,在webpack中配置.
routes:[{
path: '/user',
name: 'user', //給路由命名,設置的name要惟一!
component: User//就是第一步import的組件
},{
//路由懶加載:單頁面應用,首頁時,加載內容時間過長.運用懶加載對頁面組件進行劃分,減小首頁加載時間
path:'/Page',
name:'Page',
component:resolve => require(['@/components/Page'],resolve)
//此時component則不須要在第一步import
}]
})
複製代碼
建議在實際項目中將router配置單獨的js文件,更加清晰,不要都混在main.js中.
import router from './router'
new Vue({
el: '#app',
router,//不簡寫就是router:router,
store,
template: '<App/>',
components: {
App
} })
複製代碼
至此,一個基本的vue-router已經完成.這裏只是簡單示範,瞭解其實現步驟. 總結一下編寫vue路由時,記住要作這三類事: 1,準備工做: 在main.js中引入router.js掛載到Vue實例中. 2,配置路由實例(重點): 在router.js中引入Vue,vue-router,配置路由實例. 3,組件內配置: 就是配置router-link和router-view.
通常單頁面應用是(SPA)不會請求頁面而是隻更新視圖. vue-router提供了兩種方式來實現前端路由:Hash模式和History模式,能夠用mode參數來決定使用哪種方式.
vue-router默認使用Hash模式.使用url的hash來模擬一個完整的url.此時url變化時,瀏覽器是不會從新加載的.
Hash(即#)是url的錨點,表明的是網頁中的一個位置,僅僅改變#後面部分,瀏覽器只會滾動對應的位置,而不會從新加載頁面.#僅僅只是對瀏覽器進行指導,而對服務端是徹底沒有做用的!它不會被包括在http請求中,故也不會從新加載頁面.
同時hash發生變化時,url都會被瀏覽器記錄下來,這樣你就可使用瀏覽器的後退了.
總而言之:Hash模式就是經過改變#後面的值,實現瀏覽器渲染指定的組件.
若是你不喜歡hash這種#樣式.可使用history模式.這種模式利用了HTML5 History新增的pushState()和replaceState()方法. 除了以前的back,forward,go方法,這兩個新方法能夠應用在瀏覽器歷史記錄的增長替換功能上.使用History模式,經過歷史記錄修改url,但它不會當即向後端發送請求. 注意點:
雖然History模式能夠丟掉不美觀的#,也能夠正常的前進後退,可是刷新f5後,此時瀏覽器就會訪問服務器,在沒有後臺支持的狀況下,此時就會獲得一個404!官方文檔給出的描述是:"不過這種模式要玩好,還須要後臺配置支持.由於咱們的應用是單個客戶端應用,若是後臺沒有正確的配置,當用戶直接訪問時,就會返回404.因此呢,你要在服務端增長一個覆蓋全部狀況的的候選資源;若是url匹配不到任何靜態資源,則應該返回同一個index.html頁面."
總而言之:History模式就是經過pushState()方法來對瀏覽器的瀏覽記錄進行修改,來達到不用請求後端來渲染的效果.不過建議,實際項目仍是使用history模式.
例子:
const router = new VueRouter({
mode: 'history', //若是這裏不寫,路由默認爲hash模式
routes: [...]
})
複製代碼
當咱們常常須要把某種模式匹配到全部的路由,所有都映射到同個組件.例如:咱們有一個User組件,對於全部ID各不相同的用戶,都要使用這個組件來渲染.這時咱們就能夠配置動態路由來實現. 動態路由匹配本質上就是經過url進行傳參
爲了下面理解的方便這裏簡單介紹下經常使用的路由對象屬性,在組件內能夠經過this.$route
(不是$router
!)進行訪問.
$route.path 類型: string
字符串,對應當前路由的路徑,老是解析爲絕對路徑,如 "/foo/bar"
。
$route.params 類型: Object
一個 key/value 對象,包含了動態片斷和全匹配片斷,若是沒有路由參數,就是一個空對象。
$route.query 類型: Object
一個 key/value 對象,表示 URL 查詢參數。例如,對於路徑 /foo?user=1
,則有 $route.query.user == 1
,若是沒有查詢參數,則是個空對象。
$route .name 當前路由的名稱,若是有的話。這裏建議最好給每一個路由對象命名,方便之後編程式導航.不過記住name必須惟一!
$route.hash 類型: string
當前路由的 hash 值 (帶 #
) ,若是沒有 hash 值,則爲空字符串。
$route.fullPath 類型: string
完成解析後的 URL,包含查詢參數和 hash 的完整路徑。
$route.matched 類型: Array<RouteRecord>
一個數組,包含當前路由的全部嵌套路徑片斷的路由記錄 。路由記錄就是 routes
配置數組中的對象副本 (還有在 children
數組)。 $route.redirectedFrom 若是存在重定向,即爲重定向來源的路由的名字。
舉個例子:
routes:[{
//動態路徑參數,以冒號開頭
path:'/user/:id',
component:User
}]
複製代碼
這樣,就是使用params進行配置.像/user/foo和/user/bar都將映射到相同的路由.
this.$route.params
,能夠在每一個組件內使用.例如/user/foo在this.$route.params.id
就爲foo這裏以官方的表格示例進行展現
模式 | 匹配路徑 | $route.params |
---|---|---|
/user/:username | /user/evan | { username: 'evan' } |
/user/:username/post/:post_id | /user/evan/post/123 | { username: 'evan', post_id: 123 } |
這裏再舉一個稍微變化一下的例子,來加深理解:
routes:[
{path:'/user/:shot/foo/:id', component:shotCat}
]
複製代碼
<p>
<router-link to="/user/shot/foo">/user/shot/foo</router-link> <!--沒法匹配到對應路由-->
<router-link to="/user/shot/cat/foo">/user/shot/cat/foo</router-link> <!--沒法匹配到對應路由-->
<router-link to="/user/foo/foo/foo">/user/foo/foo/foo</router-link> <!--成功匹配,$route.params.shot爲foo;$route.params.cat爲foo;-->
<router-link to="/user/shot/foo/cat">/user/shot/foo/cat</router-link><!--成功匹配,$route.params.shot爲shot;$route.params.cat爲cat;-->
</p>
<router-view></router-view>
複製代碼
tips:
/user/foo
和 /user/bar
在使用路由參數時,複用的都是User
組件.此時組件的生命週期鉤子不會再被調用。若是你想路徑切換時,進行一些初始化操做時,能夠用如下兩種解決辦法:
$route
對象:const User = {
template: '...',
watch: {
'$route' (to, from) {
// 對路由變化做出響應...
}
}
}
複製代碼
const User = {
template: '...',
beforeRouteUpdate (to, from, next) {
// react to route changes...
// don't forget to call next()
}
}
複製代碼
在項目裏咱們能夠經過上面提到的params進行傳參.同時也能夠用query進行傳參. 舉個例子: <router-link to="/user?id=foo">foo</router-link>
vue-route會自動將?後的id=foo封裝進this.$route.query裏. 此時,在組件裏this.$route.query.id值爲'foo'. ==除了經過router-link
的to
屬性. query也能夠經過後面講到的編程式導航進行傳參==
什麼是編程式導航,編程式導航就是在vue組件內部經過this.$router
訪問路由實例,並經過this.$router.push導航到不一樣的url,進行路由映射,因此 它的做用是和<router-link :to>
是一毛同樣的! 固然,前提是你已經在routes裏配置了對應的路由對象.
通常何時用到編程式導航? 若是,你想在路由跳轉前作點其餘事情,例如權限驗證等.可是用<router-link>
的話,就直接跳轉了.此時就可使用編程式導航!
編程式導航通常都是用到router.push方法.該方法的參數能夠是一個字符串路徑,或者一個描述地址的對象.例如:
//字符串
this.$router.push('home')
//對象
this.$ruter.push({path:'home'})
//命名路由
this.$router.push({name:'user',params:{userId:2333}})
//帶查詢參數,變成/register?plan=private
this.$router.push({path:'register',query:{plan:'private'}})
複製代碼
注意:==原諒色警告==:path
和params
是不能同時生效的!,不然params會被忽略掉.因此使用對象寫法進行params傳參時,要麼就是path
加冒號:
,要麼就是像上例中的'命名路由'.經過name和params進行傳參.然而query卻並不受影響,有沒有path均可以進行傳參.
router.replace和router.push很像,寫法同樣.但實際效果不同.push是向history裏添加新記錄.而replace是直接將當前瀏覽器history記錄替換掉!
那最直接的後果是什麼呢? 舉個例子:
那何時會用到replace呢? 當你不想讓用戶回退到以前的頁面時,常見於權限驗證,驗證後就不讓用戶回退到登陸頁重複驗證.
這個方法的參數就是一個整數,意思是在history記錄中前進或後退多少步.相似window.history.go(n).這樣就能控制頁面前進或者後退多少步.
補充: 實際上不經過routes配置,也能夠用下面這種方法直接在router-link
上經過to
進行傳參. 關於to
的更詳細用法: 能夠參考官方的api文檔.用法很簡單這裏我就不重複了.
routes:[
{name:'shotCat',path:'/shotCat', component:shotCat}
]
複製代碼
<router-link :to="{ name:'shotCat',params:{paramId:'hello'},query:{queryId:'world'}}">helloWorld</router-link> <!--此時經過name匹配到路由對象shotCat.-->
<router-link :to="{ path:'/shotCat',params:{paramId:'hello'},query:{queryId:'world'}}">helloWorld</router-link> <!--此時經過path匹配到路由對象shotCat.可是!!!!!此時`paramId`並不能添加到`$route.params`裏,只有`queryId`成功添加到`$route.query`-->
複製代碼
經過兩個router-link
.能夠發現這種寫法和編程式導航的規則一毛同樣, path
和params
是不能同時生效的! 因此建議你們最好給每一個路由對象進行命名!** query
是path和name均可以正常傳參的. 這裏你們能夠經過這個官方在線例子進行修改驗證{{$route.params}}
和{{$route.query}}
是否成功傳遞. 小結:
<router-link :to="{ }">
等同於this.$router.psh()
. path
和params
是不能同時存在的!,想經過params,就得加上name屬性.query
不受影響.<router-link :to="{ }">
和this.$router.psh()
的實際效果也是同樣的.
經過to
雖然能夠進行params
,query
傳參.可是注意此時頁面url並不會改變!.因此你刷新頁面後,參數就沒有了.
<router-view/>
講以前,必須先清楚這樣一件事,一個<router-view/>
對應展現的就是一個組件 所以實現嵌套路由有兩個要點:
<router-view/>
的使用.這兩點也對應了我第4章中關於思想準備的說明.
下面個人示例仍是以上圖嵌套路由爲例進行講解. 理解了的能夠看官方示例是嵌套路由搭配動態路由使用的例子,你們能夠在此基礎上本身修改嘗試.
const router = new VueRouter({
routes: [
{ path: '/user', component: User,name:'user',
//嵌套路由就寫在children配置中,寫法和rutes同樣.
children: [
{ path: '', component: UserDefault ,name:'default',
//children:[{}] 也能夠繼續添加children嵌套
},
//若是/user下沒有匹配到其餘子路由時,User的<router-view>是什麼都不會顯示的,若是你想讓它顯示點什麼.能夠將path:''.設爲空.此時UserDefault就是默認顯示的組件.
{ path: 'foo', component: UserFoo,name:'foo'},
//此時path等同於'/user/foo',子路由會繼承父路由的路徑.可是不能寫成path:'/foo'.由於以 / 開頭的嵌套路徑會被看成根路徑,也就是說此時foo成了根路徑.而不是user.
{ path: 'bar', component: UserBar,name:'bar' }
]
}
]
})
複製代碼
<router-view/>
的使用.<div id="app">
<p>
<router-link to="/user">/user</router-link>
<router-link to="/user/foo">/user/foo</router-link>
<router-link to="/user/bar">/user/bar</router-link>
</p>
<router-view></router-view> <!--這裏展現的是User組件;一樣User的<router-view/>也被嵌套在裏面-->
</div>
複製代碼
const User = {
template: ` <div class="user"> <h2>User</h2> <router-view></router-view> </div> `
}
//User的<router-view>裏展現的就是子路由foo,bar的組件還有default默認組件
const UserDefault = { template: '<div>default</div>' }
const UserFoo = { template: '<div>foo</div>' }
const UserBar = { template: '<div>bar</div>' }
複製代碼
若是一個組件有多個視圖,來展現多個子組件.這個時候就須要用到命名視圖 官方的在線示例在這裏,你們能夠在此基礎上本身修改嘗試. 直接上個人例子:
<div id="app">
<h1>Named Views</h1>
<p>
<router-link to="/avenger">復仇者聯盟</router-link>
</p>
<router-view ></router-view>
<router-view name="ironMan"></router-view>
<router-view name="captainAmerica"></router-view>
</div>
<!--這裏咱們給其中兩個視圖命名爲ironMan和captainAmerica;沒有設置name的視圖,會得到默認命名爲default> 複製代碼
const router = new VueRouter({
routes: [
{ path: '/avenger', name:'avenger',components: {
default: stanLee,
ironMan: ironMan,
captainAmerica: captainAmerica
}
//若是有多個視圖須要展現時,之前的component換成components(加上s!!),寫成對象形式.左邊的ironMan指的就是<router-view>裏設置的name="ironMan";右邊的則指的是下面的組件ironMan.
}
]
})
const stanLee = { template: '<div>斯坦李</div>' }
const ironMan = { template: '<div>鋼鐵俠</div>' }
const captainAmerica = { template: '<div>美國隊長</div>' }
複製代碼
嵌套命名視圖: 官方的在線示例,結合了嵌套路由和命名視圖.就是兩種寫法的組合.建議初學者經過這個例子加深理解.
重定向其實就是經過路由.攔截path,而後替換url跳轉到redirect所指定的路由上. 重定向是經過 routes 配置來完成,
//從 /a 重定向到 /b
const router = new VueRouter({
routes:[
{path:'/a',rediret:'/b'}
]
})
///從 /a 重定向到 命名爲'foo'的路由
const router = new VueRouter({
routes: [
{ path: '/a', redirect: { name: 'foo' }}
]
})
//甚至是一個方法,動態返回重定向目標:
const router = new VueRouter({
routes: [
{ path: '/a', redirect: to => {
// 方法接收 目標路由 做爲參數
// return 重定向的 字符串路徑/路徑對象
const { hash, params, query } = to
//這裏使用了ES6的解構寫法,分別對應了to的hash模式,params,query參數.這裏解構就不具體說明了.
if (query.to === 'foo') {
return { path: '/foo', query: null }
}
if (hash === '#baz') {
return { name: 'baz', hash: '' }
}
if (params.id) {
return '/with-params/:id'
} else {
return '/bar'
}
}}
]
})
複製代碼
重定向是替url換路徑,達到路由跳轉.那別名就是一個路由有兩個路徑.兩個路徑都能跳轉到該路由. 舉個栗子:你可能大名叫'趙日天',但你的小名(別名)可能就叫'二狗子'.但'趙日天'和'二狗子'指代的是同一我的(路由). 別名是在rutes裏的alias進行配置:
const router = new VueRouter({
//這時,路徑'/fxxksky'和'/two-dogs' 都會跳轉到A
routes: [
{ path: '/fxxksky', component: A, alias: '/two-dogs' }
//當有多個別名時,alias也能夠寫成數組形式. alias: ['/two-dogs', 'three-dogs','four-dogs','five-dogs']
]
})
複製代碼
路由傳參,能夠經過前面介紹的params和query進行傳參.但這兩種傳參方式,本質上都是把參數放在url上,經過改變url進行的.這樣就會形成參數和組件的高度耦合. 若是我想傳參的時候,能夠更自由,擺脫url的束縛.這時就可使用rute的props進行解耦.提升組件的複用,同時不改變url.
下面就以例子進行講解: PS: 這部分官方沒有在線實例,你們能夠將我下面例子的代碼將以前的在線例子進行覆蓋就能夠了
//路由配置:
const Hello = {
props: ['name'], //使用rute的props傳參的時候,對應的組件必定要添加props進行接收,不然根本拿不到傳參
template: '<div>Hello {{ $route.params}}和{{this.name}}</div>'
//若是this.name有值,那麼name已經成功成爲組件的屬性,傳參成功
}
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/', component: Hello }, // 沒有傳參 因此組件什麼都拿不到
{ path: '/hello/:name', component: Hello, props: true }, //布爾模式: props 被設置爲 true,此時route.params (即此處的name)將會被設置爲組件屬性。
{ path: '/static', component: Hello, props: { name: 'world' }}, // 對象模式: 此時就和params沒什麼關係了.此時的name將直接傳給Hello組件.注意:此時的props需爲靜態!
{ path: '/dynamic/:years', component: Hello, props: dynamicPropsFn }, // 函數模式: 1,這個函數能夠默認接受一個參數即當前路由對象.2,這個函數返回的是一個對象.3,在這個函數裏你能夠將靜態值與路由相關值進行處理.
{ path: '/attrs', component: Hello, props: { name: 'attrs' }}
]
})
function dynamicPropsFn (route) {
return {
name: (new Date().getFullYear() + parseInt(route.params.years)) + '!'
}
}
new Vue({
router,
el: '#app'
})
複製代碼
<!--html部分-->
<div id="app">
<h1>Route props</h1>
<ul>
<li><router-link to="/">/</router-link></li>
<li><router-link to="/hello/you">/hello/you</router-link></li>
<li><router-link to="/static">/static</router-link></li>
<li><router-link to="/dynamic/1">/dynamic/1</router-link></li>
<li><router-link to="/attrs">/attrs</router-link></li>
</ul>
<router-view></router-view>
</div>
複製代碼
vue主要用於單頁面應用,此時webpack會打包大量文件,這樣就會形成首頁須要加載資源過多,首屏時間過長,給用戶一種不太友好的體驗. 若是使用路由懶加載,僅在你路由跳轉的時候才加載相關頁面.這樣首頁加載的東西少了,首屏時間也減小了. vueRouter的懶加載主要是靠Vue 的異步組件和 Webpack 的代碼分割功能,輕鬆實現路由組件的懶加載。 這裏寫法其實我在第5.3章裏的例子已經寫過,比較簡單隻須要將組件以promise形式引入便可.
routes:[
path:'/',
name:'HelloWorld',
component:resolve=>require(['@/component/HelloWorld'],resolve)
]
//此時HelloWorld組件則不須要在第一步import進來
複製代碼
把組件按組分塊能夠把路由下的全部組件都打包在同個異步塊 (chunk) 中,而且在f12的network裏面看到動態加載的組件名字. 前提條件:
output: {
path: config.build.assetsRoot,
filename: '[name].js',
// 須要配置的地方
chunkFilename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
}
複製代碼
此時在引入組件時的寫法須要使用 命名 chunk,一個特殊的註釋語法來提供 chunk name
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
複製代碼
路由導航守衛,通俗點說就是路由鉤子.做用也和生命週期鉤子相似,在路由跳轉過程進行操做控制. 導航守衛有不少鉤子,這裏我就不照搬官方文檔了.這裏你們本身先點擊閱讀完導航守衛,而後再看個人總結和代碼例子.
每一個守衛方法接收三個參數:
to: Route
: 即將要進入的目標 路由對象
from: Route
: 當前導航正要離開的路由對象
next: Function
: 必定要調用該方法來 resolve 這個鉤子。執行效果依賴 next
方法的調用參數。
next()
: 進行管道中的下一個鉤子。若是所有鉤子執行完了,則導航的狀態就是 confirmed (確認的)。
next(false)
: 中斷當前的導航。若是瀏覽器的 URL 改變了 (多是用戶手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到 from
路由對應的地址。
next('/')
或者 next({ path: '/' })
: 跳轉到一個不一樣的地址。當前的導航被中斷,而後進行一個新的導航。你能夠向 next
傳遞任意位置對象,且容許設置諸如 replace: true
、name: 'home'
之類的選項以及任何用在 router-link
的 to
prop 或 router.push
中的選項。
next(error)
: (2.4.0+) 若是傳入 next
的參數是一個 Error
實例,則導航會被終止且該錯誤會被傳遞給 router.onError()
註冊過的回調。
官方介紹的比較簡單,沒有實際栗子,下面我就經過栗子再進行詳細的說明
//1,能夠在main.js 或者在單獨的路由配置文件router.js中進行設置
router.beforeEach((to, from, next) => {
...
next();
});
//2,也能夠在組件內部設置
this.$router.beforeEach((to, from, next) => {
...
next();
});
//3,對函數及next()的詳細使用說明
router.beforeEach((to, from, next) => {
//首先to和from 實際上是一個路由對象,因此路由對象的屬性都是能夠獲取到的(具體能夠查看官方路由對象的api文檔).
//例如:我想獲取獲取to的完整路徑就是to.path.獲取to的子路由to.matched[0].
next();//使用時,千萬不能漏寫next!!!
//next() 表示直接進入下一個鉤子.
//next(false) 中斷當前導航
//next('/path路徑')或者對象形式next({path:'/path路徑'}) 跳轉到path路由地址
//next({path:'/shotcat',name:'shotCat',replace:true,query:{logoin:true}...}) 這種對象的寫法,能夠往裏面添加不少.router-link 的 to prop 和 router.push 中的選項(具體能夠查看api的官方文檔)全都是能夠添加進去的,再說明下,replace:true表示替換當前路由地址,經常使用於權限判斷後的路由修改.
//next(error)的用法,(需2.4.0+)
}).catch(()=>{
//跳轉失敗頁面
next({ path: '/error', replace: true, query: { back: false }})
})
//若是你想跳轉報錯後,再回調作點其餘的可使用 router.onError()
router.onError(callback => {
console.log('出錯了!', callback);
});
複製代碼
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// 使用方法和上面的beforeEach一毛同樣
}
}
]
})
複製代碼
這裏官方的例子說明的很詳細,這裏就直接進行引用了.
//在組件內部進行配置,這裏的函數用法也是和beforeEach一毛同樣
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`
}
}
複製代碼
官方文檔給的說明都是文字形式的,不是特別直觀.這裏就不copy了.這裏就直接以流程圖的形式進行展現(這裏參考了這位同窗的圖,在此感謝!).
一句話歸納:路由配置的meta對象裏的信息. 官方栗子:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
children: [
{
path: 'bar',
component: Bar,
// a meta field
meta: { requiresAuth: true }
}
]
}
]
})
複製代碼
從栗子能夠看出就是給路由添加了一個自定義的meta對象,並在裏面設置了一個requiresAuth狀態爲true.
從下面的另外一個官方栗子裏已經給出了答案.
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
//對matched不瞭解的建議看官方api文檔,或我7.1節的說明
//數組some方法,若是meta.requiresAuth爲ture,則返回true.此時,說明進入該路由前須要判斷用戶是否已經登陸
if (!auth.loggedIn()) { //若是沒登陸,則跳轉到登陸頁
next({
path: '/login',
query: { redirect: to.fullPath } //官方例子的這個小細節很好,經過query將要跳轉的路由路徑保存下來,待完成登陸後,就能夠直接獲取該路徑,直接跳轉到登陸前要去的路由
})
} else {
next()
}
} else {
next() // 確保必定要調用 next()
}
})
複製代碼
咱們能夠經過在meta裏設置的狀態,來判斷是否須要進行登陸驗證.若是meta裏的requiresAuth爲true,則須要判斷是否已經登陸,沒登陸就跳轉到登陸頁.若是已登陸則繼續跳轉.
此時,可能會有同窗說,前面說的path,params,query均可以存儲信息,做爲登陸驗證的狀態標記.的確,它們也能夠達到一樣的效果.若是是少許單個的驗證,使用它們問題不大. 但若是是多個路由都須要進行登陸驗證呢?path,params,query是把信息顯性地存儲在url上的.而且多個路徑都把一個相同的狀態信息加在url上.這樣就使url再也不單純,而且也很不優雅美觀. 因此要優雅要隱性地傳遞信息,就使用meta對象吧!
當年切換路由時,可使頁面滾動到你想要的某個地方,或者是保持以前滾動的位置,這時你就須要使用scrollBehavior這個方法.
注意點:
const router = new VueRouter({
mode:'history',//這個不能忘,默認是hash模式
routes: [...],
scrollBehavior (to, from, savedPosition) {
// to:要進入的目標路由對象,到哪裏去.和導航守衛的beforeEach同樣
//from:離開的路由對象,哪裏來
//savedPosition: 點擊前進/後退的時候記錄值{x:?,y:?}.而且只有經過瀏覽器的前進後退纔會觸發.
// return 指望滾動到哪一個的位置 { x: number, y: number }或者是{ selector: string, offset? : { x: number, y: number }},這裏selector接收字符串形式的hash,如'#foo',同時你還能夠經過offset設置偏移,版本須要大於2.6+
//舉個實例
if(savePosition) { //若是是瀏覽器的前進後退就,返回以前保存的位置
return savePosition;
}else if(to.hash) {//若是存在hash,就滾動到hash所在位置
return {selector: to.hash}
}else{
return {x:0,y:0}//不然就滾動到頂部
}
}
})
複製代碼