學習目的
? ? 學習Vue的必備技能情臭,必須 熟練使用 Vue-router茧痒,能夠在實際項目中運用赴精。
Vue-router介紹
? ??Vue Router 是 Vue.js?官方的路由管理器雇初。它和 Vue.js 的核心深度集成戏罢,讓構建單頁面應用變得易如反掌硝清。包含的功能有:嵌套的路由/視圖表辅斟;模塊化的、基于組件的路由配置芦拿;路由參數(shù)士飒、查詢、通配符蔗崎;基于 Vue.js 過渡系統(tǒng)的視圖過渡效果酵幕;細粒度的導航控制;帶有自動激活的 CSS class 的鏈接缓苛;HTML5 歷史模式或 hash 模式裙盾,在 IE9 中自動降級;自定義的滾動條行為。
? ? ? ? 由 前端 來控制頁面的跳轉(但其實是個單頁面)番官,根據不同的?url?地址展示不同的內容和頁面庐完。
? ? ? ? 優(yōu)點:體驗好,不需要每次從服務器獲取全部徘熔,快速展現(xiàn)給用戶门躯;
? ? ? ? 缺點:不利于SEO;使用瀏覽器的前進酷师,后退鍵的時候會重新發(fā)送請求讶凉,沒有合理的利用緩存;單頁面無法記住之前滾動的位置山孔,無法在前進和后退的時候記住滾動的位置懂讯。
Vue-router安裝
? ? ? ? 安裝? npm install vue-router??--save-dev?
? ? ? ? src 目錄下 新建 router 目錄,目錄下新建 index.js
? ? ? ? 在 main.js中引入
? ?Vue-router 核心
? ? ? ? ? ? ? 路由跳轉的方式
? ? ? ? ? ? ? ? ? ? <router-link to=' '></router-link>? ? 和? ?this.$router.push({path:' '})
????????動態(tài)路由匹配
? ? ? ? ? ? ? ? 動態(tài)路由路徑參數(shù)台颠,以冒號開頭褐望,如上圖的 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑
? ? ? ? ? ? ? ? 獲取路由的參數(shù)
? ? ? ? ? ? ? ? 當在路由中設置了 props:true 的時候
? ? ????????官方文檔中的說明
? ??????????響應路由參數(shù)的變化
? ? ? ? ? ? ? ? ? ? 當路由參數(shù)發(fā)生變化時,比如helloworld/123 導航到 helloworld/456串前,原來的組件實例會被復用瘫里。因為兩個路由都渲染同個組件,比起銷毀再創(chuàng)建荡碾,復用則顯得更加高效谨读。不過,這也意味著組件的生命周期鉤子不會再被調用坛吁。
? ??????????????????復用組件時劳殖,想對路由參數(shù)的變化作出響應的話,可以用以下兩種方式
? ? ? ? ? ? ? ? 比如 mounted ,created 不會再被調用? 拨脉, 以上 兩種方式 監(jiān)聽參數(shù)變化闷尿,作出相應的業(yè)務邏輯處理。
? ? ? 嵌套路由
? ??????????????當你訪問?/layout 時女坑,layout?的 router-view 是不會渲染任何東西填具,這是因為沒有匹配到合適的子路由。如果你想要渲染點什么匆骗,可以提供一個 空的 子路由(可以理解為默認輸出):
? ????編程式的導航
? ? ? ? ????除了使用??創(chuàng)建 a 標簽來定義導航鏈接劳景,我們還可以借助 router 的實例方法,通過編寫代碼來實現(xiàn):?this.$router.push({path:' '})
? ? ? ? ? ? 文檔示例:
router.push('home')? 碉就;// 字符串
router.push({path:'home'})盟广;??// 對象
router.push({name:'user',params:{userId:123}});??// 命名的路由
router.push({path:'register',query:{plan:'private'}})瓮钥;// 帶查詢參數(shù)筋量,變成 /register?plan=private 烹吵,獲取this.$route.query.plan
注意:如果提供了?path,params?會被忽略桨武,上述例子中的?query?并不屬于這種情況肋拔。取而代之的是下面例子的做法,你需要提供路由的?name?或手寫完整的帶有參數(shù)的?path:
const userId = 123
router.push({ name: 'user', params: { userId }})呀酸;? ? // -> /user/123
router.push({ path: `/user/${userId}` }) 凉蜂;? ? ?// -> /user/123
// 這里的 params 不生效(注意這個例子)
router.push({ path: '/user', params: { userId }}) ;? ?// -> /user
? ? ??同樣的規(guī)則也適用于?router-link?組件的?to?屬性性誉。
? ??????router.go(n)??這個方法的參數(shù)是一個整數(shù)窿吩,意思是在 history 記錄中向前或者后退多少步,類似?window.history.go(n)错览。
????????router.go(1) 纫雁;?// 在瀏覽器記錄中前進一步,等同于 history.forward( )
????????router.go(-1)倾哺; // 后退一步記錄轧邪,等同于 history.back( )
????????router.go(3);??// 前進 3 步記錄
? ??命名路由 和 命名視圖
? ??????????????命名路由?
? ??????這跟代碼調用?router.push()?是一樣的:
? ?????? this.$router.push({ name:'Helloworld',params:{id:123}});
? ??????????????命名視圖
? ??????????????有時候想同時 (同級) 展示多個視圖悼粮,而不是嵌套展示闲勺,例如創(chuàng)建一個布局曾棕,有?sidebar?(側導航) 和?main?(主內容) 兩個視圖扣猫,這個時候命名視圖就派上用場了。你可以在界面中擁有多個單獨命名的視圖翘地,而不是只有一個單獨的出口申尤。如果?router-view?沒有設置名字,那么默認為?default衙耕。
? ? ? ? ? ? ? ? ? ? ? ? 文檔示例
? ? ??? ? ? ? ? ? 嵌套命名視圖
? ??????????重定向 和 別名
? ? ? ? ? ? ? ? 重定向
? ? ? ? ? ? ? ? ? ? 重定向 通過?routes?配置來完成
? ? ? ? ? ? ? ? ? ? 別名 (文檔示例)
? ??????????????/a?的別名是?/b昧穿,意味著,當用戶訪問?/b?時橙喘,URL 會保持為?/b时鸵,但是路由匹配則為?/a,就像用戶訪問?/a?一樣
const router = new VueRouter({
????????????????routes: [
????????????????????{ path: '/a', component: A, alias: '/b' }
????????????????]})
? ??????????導航守衛(wèi)
? ??????????“導航”表示 路由正在發(fā)生改變厅瞎。? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??????????????vue-router?提供的導航守衛(wèi)主要用來通過跳轉或取消的方式守衛(wèi)導航饰潜。有多種機會植入路由導航過程中:全局的, 單個路由獨享的, 或者組件級的。
? ? ? ? ? ? ? 記住參數(shù)或查詢的改變并不會觸發(fā)進入/離開的導航守衛(wèi)和簸。你可以通過觀察?$route?對象來應對這些變化彭雾,或使用?beforeRouteUpdate?的組件內守衛(wèi)。
? ? ? ? ? ? ? ? ? ? 個人的理解锁保,導航守衛(wèi)有點類似 中間件薯酝,進入 路由 前 先通過守衛(wèi)半沽,來判斷是否可以通過,進而到達頁面吴菠。
? ?????????????全局守衛(wèi) (在定義router的 地方定義)
? ??????????????????全局前置守衛(wèi)?router.beforeEach
? ??????????????????????每個守衛(wèi)方法接收三個參數(shù):
? ??????????????????????to: Route: 即將要進入的目標?路由對象
? ??????????????????????from: Route: 當前導航正要離開的路由
? ??????????????????????next: Function: 一定要調用該方法來?resolve?這個鉤子者填。執(zhí)行效果依賴?next?方法的調用參數(shù)。
? ??????????????????????next(): 進行管道中的下一個鉤子橄务。如果全部鉤子執(zhí)行完了幔托,則導航的狀態(tài)就是?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?的參數(shù)是一個?Error?實例驳糯,則導航會被終止且該錯誤會被傳遞給?router.onError()?注冊過的回調篇梭。
? ??????????????????????確保要調用?next?方法,否則鉤子就不會被 resolved酝枢。
? ??????????????????全局解析守衛(wèi)???router.beforeResolve
? ? ? ? ? ? ? ? ? ? ????跟?全局前置守衛(wèi) 一樣恬偷,接收三個參數(shù)
? ??????????????????????這和?router.beforeEach?類似,區(qū)別是在導航被確認之前帘睦,同時在所有組件內守衛(wèi)和異步路由組件被解析之后袍患,解析守衛(wèi)就被調用。
????????????????????????確保要調用?next?方法
? ??????????????????全局后置鉤子?? router.afterEach
? ??????????????????????不會接受?next?函數(shù)也不會改變導航本身
? ? ? ? ? ? 路由獨享的守衛(wèi)(在路由內定義)
? ??????????????????這些守衛(wèi)與全局前置守衛(wèi)的方法參數(shù)是一樣的竣付。
? ??????????組件內的守衛(wèi)(在組件內定義)
? ? ? ? ? ? ? ? ? ? ?beforeRouteEnter?守衛(wèi)?不能?訪問?this诡延,因為守衛(wèi)在導航確認前被調用,因此即將登場的新組件還沒被創(chuàng)建。不過古胆,你可以通過傳一個回調給?next來訪問組件實例肆良。在導航被確認的時候執(zhí)行回調,并且把組件實例作為回調方法的參數(shù)逸绎。
? ??????????????????beforeRouteEnter(to,from,next){
????????????????????????next( vm => {
????????????????????????????// 通過 `vm` 訪問組件實例
????????????????????})}
? ??????????????????注意?beforeRouteEnter?是支持給?next?傳遞回調的唯一守衛(wèi)惹恃。對于?beforeRouteUpdate?和?beforeRouteLeave?來說,this?已經可用了桶良,所以不支持傳遞回調座舍,因為沒有必要了。
? ??????????????????beforeRouteUpdate(to,from,next){
????????????????????????// just use `this`
????????????????????????this.name = to.params.name陨帆;
????????????????????????next()曲秉;
????????????????????}
? ??????????????????這個離開守衛(wèi)通常用來?禁止用戶在還未保存修改前突然離開?采蚀。該導航可以通過?next(false)?來取消。
? ??????????????????beforeRouteLeave(to,from,next){
????????????????????????const answer = window.confirm('Do you really want to leave? you have ????????????????????????????????????unsaved changes!')承二;
????????????????????????if(answer){
????????????????????????????????next()榆鼠;
????????????????????????????}else{
????????????????????????????????next(false);
????????????????????????????}}
??????????????完整的導航解析流程
????????導航被觸發(fā)亥鸠。
????????在失活的組件里調用離開守衛(wèi)妆够。
????????調用全局的?beforeEach?守衛(wèi)。
????????在重用的組件里調用?beforeRouteUpdate?守衛(wèi) (2.2+)负蚊。
????????在路由配置里調用?beforeEnter神妹。
????????解析異步路由組件。
????????在被激活的組件里調用?beforeRouteEnter家妆。
????????調用全局的?beforeResolve?守衛(wèi) (2.5+)鸵荠。
????????導航被確認。
????????調用全局的?afterEach?鉤子伤极。
????????觸發(fā) DOM 更新蛹找。
????????用創(chuàng)建好的實例調用?beforeRouteEnter?守衛(wèi)中傳給?next?的回調函數(shù)。
?????????過渡動效
? ? ? ? ? ? ? ? ?<router-view>是基本的動態(tài)組件哨坪,所以我們可以用 <transition>組件給它添加一些過渡效果:
? ??????????????????fade-enter:進入過渡的開始狀態(tài)庸疾,元素被插入時生效,只應用一幀后立刻刪除当编。
????????????????????fade-enter-active:進入過渡的結束狀態(tài)届慈,元素被插入時就生效,在過渡過程完成后移除凌箕。
????????????????????fade-leave:離開過渡的開始狀態(tài)拧篮,元素被刪除時觸發(fā)词渤,只應用一幀后立刻刪除牵舱。
????????????????????fade-leave-active:離開過渡的結束狀態(tài),元素被刪除時生效缺虐,離開過渡完成后被刪除芜壁。
? ? ? ? ? ? ? ? ? ? 數(shù)據獲取(以下為 文檔示例 )
? ? ? ? ? ? ? ? ? ? 有時候高氮,進入某個路由后慧妄,需要從服務器獲取數(shù)據。例如剪芍,在渲染用戶信息時塞淹,你需要從服務器獲取用戶的數(shù)據。我們可以通過兩種方式來實現(xiàn):
? ??????????????????導航完成之后獲取:先完成導航罪裹,然后在接下來的組件生命周期鉤子中獲取數(shù)據饱普。在數(shù)據獲取期間顯示“加載中”之類的指示运挫。
? ??????????????????導航完成之前獲取:導航完成前,在路由進入的守衛(wèi)中獲取數(shù)據套耕,在數(shù)據獲取成功后執(zhí)行導航谁帕。
????????????????????從技術角度講,兩種方式都不錯 —— 就看你想要的用戶體驗是哪種冯袍。
? ??????????????????????導航完成后獲取數(shù)據
? ??????????????????當你使用這種方式時匈挖,我們會馬上導航和渲染組件,然后在組件的?created?鉤子中獲取數(shù)據康愤。這讓我們有機會在數(shù)據獲取期間展示一個 loading 狀態(tài)儡循,還可以在不同視圖間展示不同的 loading 狀態(tài)。
假設我們有一個?Post?組件征冷,需要基于?$route.params.id?獲取文章數(shù)據:
? ??????????????????????????在導航完成前獲取數(shù)據
????????????????????通過這種方式贮折,我們在導航轉入新的路由前獲取數(shù)據。我們可以在接下來的組件的?beforeRouteEnter守衛(wèi)中獲取數(shù)據资盅,當數(shù)據獲取成功后只調用?next?方法调榄。