vue框架的優缺點,一文讓你徹底搞懂 vue-Router
路由是網絡(luo)工程里(li)面的(de)專業術語(yu),就(jiu)是通過互聯把信息從源地址傳(chuan)輸到(dao)目的(de)地址的(de)活(huo)動。本質上(shang)就(jiu)是一(yi)種對應(ying)關系。分為前(qian)端(duan)路由和(he)后端(duan)路由。
后端路由:
URL 的(de)請求(qiu)地(di)址與服務器上的(de)資(zi)源(yuan)對應,根據不同的(de)請求(qiu)地(di)址返回不同的(de)資(zi)源(yuan)。
前端路由:
在單頁面(mian)應用(yong)中,根據用(yong)戶觸發(fa)的事件,改(gai)變URL在不刷新(xin)頁面(mian)的前提(ti)下,改(gai)變顯示(shi)內容。
1、前端路由實現原理
URL 的 hash 模式
改變 hash 值的時候,#是一個位置標識(shi)符,可(ke)以進行頁(ye)面內的位置跳轉(zhuan),并不會刷新頁(ye)面。
通過 location.hash 改(gai)變頁(ye)面(mian)的(de) hash 值,如:
我們發現頁面并不會刷新。
URL 的 history 模式
history 模式,有 5 種改變 url 而(er)不(bu)刷新頁面的方(fang)法(fa),分別為:
history.pushState() //壓入棧history.replaceState() // 替換當前url,不能返回上一個頁面history.back() //返回上一個頁面history.go(n) //n的值可以是大于0的,表示向前幾個,小于0時,表示向后退幾個history.forward() //向前一步
history.go(-1) 等價于 history.back()
history.go(1) 等價于(yu) history.forward()
前端(duan)三(san)大框架,都有(you)自己(ji)的路由:
Angular 有 ngRouter
React 有(you) ReactRouter
Vue 有(you) vue-Router
2、vue-Router 基本使用
2.1、安裝
npm install vue-router --save
使(shi)用(yong) vue-router 的前提是 vue 必須使(shi)用(yong)
在(zai) router 文件夾(jia)內 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 中(zhong),vue 實(shi)例化中(zhong),把 router 掛載的(de) vue 上。
let app = new Vue({ el:'#app', data:{}, // 掛載到vue上面 router, })
2.5、頁面上(shang)添加 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 是用來(lai)占位的(de),將路由對應(ying)的(de)組(zu)件展示到(dao)該位置(zhi)。
3、router 的模式
路由模式有兩種,hash 和 history 模式。
3.1、hash 模式
vue-router 默認使用的是 hash 模式。
hash 的 url 中錨(mao)點(dian)就是 #xx 號后的內容,通(tong)過錨(mao)點(dian)作(zuo)為路由地址(zhi),我們通(tong)常改變的是#號后的內容,實現瀏(liu)覽(lan)器渲染(ran)指定的組件,錨(mao)點(dian)發(fa)生改變會觸發(fa) onhashchange 事件。
3.2、history 模式
history就(jiu)是正常(chang)的 url,沒有#號(hao),使用的時候需要服務器進行配置。history模式下,對(dui)應的方法(fa)與上(shang)述 5 個方法(fa)是一樣的。
vue-router 中可以指定(ding)需要的(de)模式:
const router = new VueRouter({ mode:'history'})
4、router-link的屬性
router-link 默認會(hui)渲染(ran)成 a 標簽,但(dan)是(shi)有時候(hou)你想渲染(ran)成別的標簽也(ye)是(shi)可以的。
4.1、tag 屬性
tag屬性是用來(lai)設置 router-link 標簽(qian)渲(xuan)染類型的,如我們想(xiang)把 router-link 渲(xuan)染成 button,如:
<router-link to="/home" tag="button">首頁</router-link>
查看渲染后的(de)(de)元素,發現(xian)變成 button 標簽(qian)了,對(dui)應(ying)的(de)(de) to 添加的(de)(de)屬性值就會失(shi)效。此時(shi)點擊無法跳轉到對(dui)應(ying)內容,可繼續閱讀下(xia)邊跳轉方式。
除了 button ,tag 的屬性值還可以是其他任意標簽(qian),router-link 自(zi)動渲染(ran)成對應的標簽(qian)。
4.2、replace 屬性
replace與上邊 history 模式中的 replaceState 對應,跳(tiao)轉的時候不會留下 history 記錄,指定replace 的情況(kuang)下,不能(neng)返回上一頁(ye)。
<router-link to="/home" replace>首頁</router-link>
4.3、active-class
active-class 設置 router-link 點擊當前(qian)選中(zhong)的類(lei)名,默(mo)認情況下(xia)類(lei)名為:router-link-active
<a href="#/" aria-current="page" class="router-link-exact-active router-link-active"> 首頁 </a>
設(she)置當前元素樣式需(xu)要(yao)設(she)置到:router-link-active。
設置 active-class ,如:
<router-link to="/" active-class="active">首頁</router-link>// router-link-active 類名會被替換成 active
如(ru)果需要把全(quan)局的 router-link 的選擇類名(ming)都(dou)修改(gai)成自定義的,一個(ge)一個(ge)單獨設(she)置工作量太大,可(ke)以在 router 中統(tong)一設(she)置。
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、通過(guo) js 實現跳(tiao)轉(zhuan)
// 簡單寫法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、動態路由
在(zai)某些情況下,一個頁面的 path 路徑可能是不確定的,如:希望(wang)的路徑為 /user/123或 /user/456 。后邊的值為用戶(hu) 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 進(jin)行傳參(can)
<router-link to="/user?id=123"></router-link>//取值時this.$route.query.id
另外,this.$router.addRoutes([]) 也可以添加動態路由,里面傳的是一個(ge)數(shu)組,與 routes 配(pei)置(zhi)一樣。
7、路由的懶加載
懶加(jia)載(zai)通俗的講就是使用的時候(hou)再加(jia)載(zai),不使用的時候(hou)不加(jia)載(zai)。
打包構建應用程(cheng)序(xu)的(de)(de)時候,js包會變得很(hen)大,影響加(jia)載速度,如果(guo)我們能(neng)把不同路由(you)(you)對(dui)應的(de)(de)組件分割成(cheng)不同的(de)(de)代(dai)碼塊,然后訪問路由(you)(you)的(de)(de)時候才(cai)加(jia)載對(dui)應的(de)(de)組件,這樣就(jiu)更加(jia)高(gao)效了。
路由懶加載到底做了什么呢?主(zhu)要(yao)作用就是將路(lu)由對(dui)應的組件打包成一個js代碼塊,只有路(lu)由訪問的時候,才加載(zai)對(dui)應的 js 。
//直接引用的import Home from './component/home'const routes = [ { path:'/home', component:Home } ]//懶加載const routes = [ { path:'/home', component:()=>{ import('./component/home') } } ]
8、嵌套路由
實際(ji)應(ying)用中,通常由多(duo)層嵌套的(de)組(zu)件組(zu)合而成(cheng)。
實現步驟:
第一:創建對(dui)應的(de)子(zi)組件,并且在(zai)路(lu)(lu)由映射中配置對(dui)應的(de)子(zi)路(lu)(lu)由。
第二:組件內(nei)部(bu)使(shi)用(yong) 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") }, ] }, ] }
訪問(wen) user 組件時,路(lu)由為:/body/manager/user
注意:嵌套路由設置 path 時,不(bu)能(neng)添加 “/”,否則(ze)路由就(jiu)變了。
{ path: "/user", component: ()=> import( "../views/manager/user.vue") }//此時訪問路由就變成了 " /user "
9、router 與 route 區別
試著在main.js 打(da)印(yin) router 在任意組(zu)件內(nei)打(da)印(yin) this.$router,打(da)印(yin)結果如圖(tu):
我們(men)發現(xian)兩(liang)個(ge)結果是(shi)一模一樣的。這樣我們(men)就不難理解下(xia)面的意思了。
router 為 VueRouter 實例(li),擁有自己的方法(fa),如:使用 new VueRouter創建的實例(li),想要導(dao)航(hang)到(dao)不同url,可以使用 router.push ,跳轉方式中有介紹。
route 為當(dang)前(qian)活躍狀態路由(you)對(dui)象,有(you)當(dang)前(qian)路由(you)的信息,可以(yi)通(tong)過該對(dui)象,獲取 path、params參數、query參數、name、matched、hash
10、路由守衛
為什么使用導航守衛?我們(men)來考慮一個需求:在 SPA應(ying)用中,網頁標題(ti)跟著(zhu)頁面切換如何(he)變動(dong)?
// 在對應的組件內添加created(){ document.title="測試"} 訪問該組件時,標題自動切換為 ”測試“
如果(guo)使用(yong)上(shang)述方法,那么對應已開發的組件(jian)有多(duo)少個,我們就得添加多(duo)少次,實(shi)在是太麻煩了,所以(yi)我們要(yao)借助路由(you)守衛,統(tong)一修改,也(ye)便于維護。
10.1、全局守衛
1>、使用 router.beforeEach 注冊一個(ge)全局前置守衛,只要路由(you)變動時,都會經過它。beforeEach 接收的(de)參數(shu)是(shi)一個(ge)函(han)數(shu),包含的(de)參數(shu)有三個(ge)。
router.beforeEach((to,from,next)=>{// 路由從 from 跳轉到 to // 我們只需要在路由上增加一個 name屬性就可以了 document.title = from.name next() })
注(zhu)意:上(shang)述(shu)三(san)個參數順序不(bu)能改變。next 不(bu)能丟,必(bi)須添加,否則頁面跳轉(zhuan)的時候沒法到下一步(bu),卡在空(kong)白區(qu)域(yu)。
2>、使用(yong) router.afterEach 注冊(ce)一個(ge)全(quan)局后置守衛。
router.afterEach((to,from)=>{ console.log('后置守衛') })
這兩個守衛都是全局守衛,afterEach 是在(zai)路由跳(tiao)轉完成(cheng)才執行(xing)的,所以(yi)不需要 next 。參數只有兩個。
10.2、路由獨享守衛(wei)
路(lu)由(you)配(pei)置上直接定義的守衛,用法與全局守衛一(yi)致(zhi),只是將(jiang)其(qi)放在其(qi)中(zhong)一(yi)個路(lu)由(you)對象中(zhong),只有這個路(lu)由(you)下起(qi)作用。
{ path: "/test", name: "測試", component: ()=> import( "../views/manager/test.vue"), beforeEnter:(to,from,next)=>{ console.log('test進入前') next() } }
這些守(shou)衛與全局前置(zhi)守(shou)衛的方法參(can)數是一樣的。
10.3、組件內守衛
可以在路(lu)由組(zu)件(jian)(jian)內(nei)直(zhi)接(jie)定義路(lu)由導航(hang)守衛(wei),定義在組(zu)件(jian)(jian)內(nei)的就是組(zu)件(jian)(jian)內(nei)守衛(wei)。
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` } }
注意(yi):beforeRouteLeave 離開路(lu)(lu)由(you)時(shi)執行,必須(xu)添(tian)加 next,否則無(wu)法正常跳轉到下一(yi)個路(lu)(lu)由(you)。
11、keep-alive
切換(huan)路由的時(shi)(shi)候頁面每次(ci)都會(hui)重(zhong)新渲染,我們有的組(zu)件會(hui)存在一些數據需要(yao)保(bao)留,不希望來回切換(huan)時(shi)(shi)每次(ci)都重(zhong)新渲染,所以就使用(yong) keep-alive 包(bao)裹(guo)組(zu)件,這樣只有第一次(ci)執行(xing)加載時(shi)(shi)會(hui)執行(xing) created mounted 等鉤(gou)子函數。
keep-alive 是 Vue 內置(zhi)的(de)一個組(zu)(zu)件(jian),可以使(shi)被包含的(de)組(zu)(zu)件(jian)保留狀態,或避免重新渲染(ran)。
<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>
添(tian)加 keep-alive 組(zu)(zu)件,切換的(de)時(shi)候(hou),組(zu)(zu)件只會(hui)在第一(yi)次的(de)時(shi)候(hou)渲(xuan)染(ran)組(zu)(zu)件,之后進(jin)入不(bu)會(hui)重(zhong)新(xin)渲(xuan)染(ran)。
11.1、keep-alive 特(te)定方法
activated(){ console.log('activated') },deactivated(){ console.log("deactivated") }
這兩個(ge)函數,只有(you)組件被保持了狀態,使(shi)用keep-alive時,才是有(you)效(xiao)會(hui)執行的。
keep-alive生命周(zhou)期執行順序:
created -> mounted -> activated
deactivated 在(zai)退出后才會觸(chu)發
11.2、keep-alive 屬(shu)性(xing)
keep-alive 有兩個非常重要的(de)屬性:
include - 字符串或(huo)正則(ze)表達式,只(zhi)有匹配組件的時候才會(hui)被緩存
exclude - 字符串或正則表達式,任何匹配的組件都不會被(bei)緩存
<keep-alive include="test"> <router-view></router-view></keep-alive>//test組件 添加name屬性<template> <div> test </div></template><script> export default { name:'test' } <script>
此時只有 test 組(zu)件會被緩(huan)存(cun),其(qi)他任意組(zu)件都不會緩(huan)存(cun)。
如果還有其他組件(jian)同(tong)時需要被緩存,include可添(tian)加多個值,只用逗號隔開,但不能添(tian)加空(kong)格。
<keep-alive include="test,user"> <router-view></router-view></keep-alive>
exclude的(de)使用:
<keep-alive exclude="test,user"> <router-view></router-view></keep-alive>
正(zheng)好與上(shang)實(shi)例相(xiang)反,只有(you) test,user 兩個組件(jian)不被(bei)緩存(cun),其他的被(bei)緩存(cun)。