1. 什么是前端路由
- 路由在我們網(wǎng)站開發(fā)中非常常見
- 比如我們?cè)趯W(xué)習(xí)html基本內(nèi)容的時(shí)候?qū)W到的在一個(gè)地方設(shè)置錨鏈接著蟹,這個(gè)錨鏈接就是我們的前端路由鳍悠,他會(huì)在地址欄中在所有url后面加上一個(gè)#井號(hào),這樣就可以保證所有的跳轉(zhuǎn)只會(huì)在前端進(jìn)行,而且Vue中的跳轉(zhuǎn)不限于只是頁面的滾動(dòng),展示指定的位置等等
- 我們將這個(gè)錨鏈接后面的內(nèi)容稱為哈希地址,這個(gè)哈希地址會(huì)指向一個(gè)位置珍策,在我們點(diǎn)擊的時(shí)候會(huì)根據(jù)url的改變?nèi)?zhí)行跳轉(zhuǎn)的動(dòng)作
- 在Vue中我們可以通過這種方式實(shí)現(xiàn)前端頁面間進(jìn)行跳轉(zhuǎn),而不用向服務(wù)器請(qǐng)求新的頁面
- 這種方式也可以為頁面?zhèn)鬟f參數(shù)宅倒,我們可以通過這種方式將一些特定的數(shù)據(jù)傳輸給其他頁面
- 后端路由是用來分配后端資源的攘宙,而前端路由是用于頁面之間跳轉(zhuǎn)的
- 在spa應(yīng)用程序中通過這種哈希的方式來實(shí)現(xiàn)頁面的切換的方式我們就稱為前端路由
2. Vue中實(shí)現(xiàn)路由
- 我們?cè)赩ue中實(shí)現(xiàn)路由需要用到Vue-router這一庫,他也是依賴Vue的,因此需要在Vue導(dǎo)入完之后才能使用
- 安裝命令為:npm install vue-router
- 之后在頁面直接引用即可
- 使用Vue-router的方式一共有以下幾個(gè)步驟:
- 引入包資源
- 創(chuàng)建一個(gè)路由對(duì)象蹭劈,因?yàn)楫?dāng)我們?cè)陧撁嬷幸盟馁Y源包的是時(shí)候我們的Vue身上就有了一個(gè)Vue-router的構(gòu)造函數(shù)疗绣,叫做VueRouter,也就是說我們需要用創(chuàng)建對(duì)象的方式來創(chuàng)建這個(gè)對(duì)象铺韧,當(dāng)我們把資源包引進(jìn)來之后我們的URL地址后面就會(huì)出現(xiàn)一個(gè)井號(hào)多矮,后期我們將會(huì)使用這個(gè)特性來匹配路由規(guī)則
- 在創(chuàng)建的路由對(duì)象身上傳入路由配置對(duì)象,也就是構(gòu)建我們的路由表哈打,其中有幾個(gè)參數(shù)塔逃,第一個(gè)是routes對(duì)象,這個(gè)配置對(duì)象就是表示路由匹配規(guī)則料仗,我們可以把我們定義的規(guī)則寫道這個(gè)對(duì)象內(nèi)部湾盗,這是個(gè)數(shù)組對(duì)象,其中的元素都是一個(gè)個(gè)對(duì)象,例如
{path:"/login",component:loginComp}
其中這里展示出來的兩個(gè)屬性是必須要的立轧,也就是說我們需要直到路由名稱格粪,并且知道路由指向的組件
- 將創(chuàng)建好的路由對(duì)象掛載到我們的Vue實(shí)例身上,我們這時(shí)候可以將Vue實(shí)例中的route對(duì)象設(shè)置為我們定義的路由對(duì)象
- 在html頁面中為路由對(duì)象留下一個(gè)占位符氛改,使用<router-view>這個(gè)標(biāo)簽來實(shí)現(xiàn)占位
- 使用超鏈接來進(jìn)行切換帐萎,只要在超鏈接的herf屬性中添加路由的地址,便可以在占位的地方展示路由的內(nèi)容胜卤,注意吓肋,在herf中添加的時(shí)候需要在前面加上一個(gè)井號(hào),如:
<a href='#/login'>登陸組件展示</a>
這樣的方式來完成我們的設(shè)置
- 之后Vue將會(huì)監(jiān)聽url的變化瑰艘,如果出現(xiàn)路由的話就便將路由所指向的內(nèi)容展示到特定位置
html
<div id="app">
<div>{{message}}</div>
<router-view></router-view>
</div>
<template id="loginTemp">
<div>
<h1>登陸組件</h1>
</div>
</template>
<template id="registTemp">
<div>
<h1>注冊(cè)組件</h1>
</div>
</template>
// 創(chuàng)建模板字符串變量是鬼,在這里必須要用這種方式創(chuàng)建完一次,之后再Vue實(shí)例上面構(gòu)建一次
let logincomp = {
template: "#loginTemp",
data: function () {
return {
userName: 'xxxxx'
}
}
}
let registcomp = {
template: "#registTemp"
}
//創(chuàng)建路由對(duì)象
let router = new VueRouter({
//路由匹配規(guī)則
routes: [{
path: '/login',
component: logincomp
},
{
path: '/regist',
component: registcomp
}
]
})
let vm = new Vue({
el: '#app',
data: {
message: "yerts"
},
//注冊(cè)組件
components: {
logincomp,
registcomp
},
//注冊(cè)路由
router: router,
})
- 這里我們會(huì)想紫新,只用在html文件里面聲明一次均蜜,然后再Vue實(shí)例里面掛載不就可以了嗎,但是我們發(fā)現(xiàn)這樣做的話路由就會(huì)提示組件沒有被聲明芒率,因此需要先將組件定義好囤耳,然后在Vue實(shí)例里面再掛載,再進(jìn)行其他數(shù)據(jù)綁定操作
- 之后如果有父組件想要給子組件傳值的話偶芍,也可以將內(nèi)容直接放在router-view這個(gè)標(biāo)簽里面
3. router-link的使用
- 在上面的例子中我們每次給url地址加上跳轉(zhuǎn)鏈接的時(shí)候都需要一個(gè)a鏈接充择,并且在href的前面加上#來實(shí)現(xiàn)跳轉(zhuǎn),這樣做其實(shí)是很麻煩的匪蟀,而且我們也控制其被選中的高亮提示也比較麻煩椎麦,因此vue-router提供了它自己的解決方案,就是router-link標(biāo)簽材彪,這個(gè)標(biāo)簽類似于超鏈接標(biāo)簽观挎,有自己的被選中類琴儿,我們可以通過設(shè)置這個(gè)類的樣式輕松實(shí)現(xiàn)對(duì)被選中的標(biāo)簽的定制
- router-link它自帶#在前面,因此使用這個(gè)會(huì)大大減少我們的工作量嘁捷,只需要在其to屬性上加上我們的路由地址即可完成跳轉(zhuǎn)
html
<div id="app">
<div>{{message}}</div>
<router-link tag='span' to="/login">登陸</router-link>
<router-link tag='span' to="/regist">注冊(cè)</router-link>
<router-view :parent-message="messageForSon"></router-view>
</div>
- 我們可以控制router-link身上的router-link-active類來設(shè)置其被選中的樣式
- 我們也可以通過設(shè)置其tag屬性來改變其被渲染到頁面的時(shí)候展示的標(biāo)簽的類型
- 同樣我們也可以根據(jù)自己的需求來給這個(gè)類更改名稱
- 我們可以在路由的配置選項(xiàng)中將linkActiveClass更改為我們自己想要的名稱造成,之后我們對(duì)這個(gè)名稱設(shè)置類的樣式即可
直接給選中類設(shè)置樣式
.router-link-active {
background-color: aquamarine;
}
設(shè)置路由對(duì)象的激活屬性
//創(chuàng)建路由對(duì)象
let router = new VueRouter({
//路由匹配規(guī)則
routes: [{
path: "/",
redirect: '/login'
}, {
path: '/login',
component: logincomp
},
{
path: '/regist',
component: registcomp
}
],
linkActiveClass: "myActive"
})
.myActive {
background-color: aquamarine;
}
- 我們也可以在路由容器外部加上transition標(biāo)簽,添加我們的切換動(dòng)畫
- 用動(dòng)畫的mode屬性完成先出去后進(jìn)來等效果
4. 前端中的重定向redirect
- 在一些頁面的首頁默認(rèn)進(jìn)來的時(shí)候展示的內(nèi)容會(huì)是一些我們?cè)诼酚蓪?duì)象中已經(jīng)定義過的一些內(nèi)容
- 如果我們監(jiān)聽根路徑的時(shí)候同樣讓其指向我們想要展示的組件的話會(huì)產(chǎn)生一個(gè)兩個(gè)鏈接都指向同一個(gè)地方的錯(cuò)覺
- 為了解決這個(gè)問題雄嚣,我們可以在路由配置表里面將根路徑指向的內(nèi)容上加一個(gè)redirect選項(xiàng)晒屎,并且將其值設(shè)置為我們想指向的內(nèi)容
- 這樣的話我們?cè)L問首頁的話會(huì)自動(dòng)跳轉(zhuǎn)到login頁面
5. 在路由里面定義參數(shù)
通過router-link中的to中加上參數(shù)來傳遞參數(shù)
- 定義路由的參數(shù)有兩種方式
- 第一種是在路由的鏈接中在后面加上
/login?id=123&name=yerts
這類參數(shù),這樣的話就可以在組件內(nèi)部通過this.$router.qurey.id
或者this.$router.qurey.name
來獲取路由鏈接傳遞的參數(shù)缓升,并且直接可以在組件內(nèi)部使用這兩個(gè)變量
<div id="app">
<div>{{message}}</div>
<router-link to="/login?userName=yerts&userId=001">登陸</router-link>
<router-link to="/regist">注冊(cè)</router-link>
<router-view :parent-message="messageForSon"></router-view>
</div>
<template id="loginTemp">
<div>
<h1>登陸組件</h1>
{{userName}}----{{userId}}----{{parentMessage}}
</div>
</template>
<template id="registTemp">
<div>
<h1>注冊(cè)組件</h1>
</div>
</template>
// 創(chuàng)建模板字符串變量鼓鲁,在這里必須要用這種方式創(chuàng)建完一次,之后再Vue實(shí)例上面構(gòu)建一次
let logincomp = {
template: "#loginTemp",
data: function () {
return {
userName: 'xxxxx',
userId: 0
}
},
created: function () {
this.userName = this.$route.query.userName
this.userId = this.$route.query.userId
},
props: ["parentMessage"]
}
let registcomp = {
template: "#registTemp"
}
//創(chuàng)建路由對(duì)象
let router = new VueRouter({
//路由匹配規(guī)則
routes: [{
path: "/",
redirect: '/login'
}, {
path: '/login',
component: logincomp
},
{
path: '/regist',
component: registcomp
}
],
linkActiveClass: "myActive"
})
let vm = new Vue({
el: '#app',
data: {
message: "yerts",
messageForSon: "info"
},
//注冊(cè)組件
components: {
logincomp,
registcomp
},
//注冊(cè)路由
router: router,
})
- 這樣操作帶來的好處就是不用修改我們的path匹配規(guī)則仔沿,只需要在我們的link-to中加入我們的參數(shù)即可
- 同時(shí)也可以做到從一個(gè)路由獲取數(shù)據(jù)發(fā)送到一個(gè)組件
通過params來傳遞參數(shù)
- 我們也可以在路由匹配規(guī)則中加上占位符,讓路由在進(jìn)行跳轉(zhuǎn)的時(shí)候強(qiáng)制加上參數(shù)尺棋,一般占位符要寫在我們的路由后面封锉,并且都是冒號(hào)開頭,后面跟跟上我們參數(shù)的名字如path:
'/login/:userName'
也就是說將來我們的login斜線后面的內(nèi)容作為id來解析出來再后期進(jìn)行使用
- 之后在進(jìn)行跳轉(zhuǎn)的時(shí)候我們?cè)趖o屬性的后面跟一個(gè)id就可以了
- 但是怎么將解析到的內(nèi)容用到我們組件內(nèi)部呢膘螟?
- 我們這個(gè)時(shí)候就可以使用$route對(duì)象的params屬性了成福,這個(gè)屬性里面就存放了我們解析得到的內(nèi)容
<div id="app">
<div>{{message}}</div>
<router-link to="/login?userName=yerts&userId=001">登陸</router-link>
<router-link to="/regist/pary">注冊(cè)</router-link>
<router-view :parent-message="messageForSon"></router-view>
</div>
<template id="loginTemp">
<div>
<h1>登陸組件</h1>
{{userName}}----{{userId}}----{{parentMessage}}
</div>
</template>
<template id="registTemp">
<div>
<h2>{{userName}}</h2>
<h1>注冊(cè)組件</h1>
</div>
</template>
let registcomp = {
template: "#registTemp",
data() {
return {
userName: ''
}
},
created() {
this.userName = this.$route.params.userName
},
}
//創(chuàng)建路由對(duì)象
let router = new VueRouter({
//路由匹配規(guī)則
routes: [{
path: "/",
redirect: '/login'
}, {
path: '/login',
component: logincomp
},
{
path: '/regist/:userName',
component: registcomp
}
],
linkActiveClass: "myActive"
})
- 這樣就可以實(shí)現(xiàn)強(qiáng)制傳參了
6. children實(shí)現(xiàn)路由的嵌套
- 要知道當(dāng)前我們創(chuàng)建的所有路由的規(guī)則都是平級(jí)的,也就是沒有實(shí)現(xiàn)一個(gè)路由下面又嵌套了另一個(gè)路由這種
- 這種情況下我們需要在路由規(guī)則里面實(shí)現(xiàn)路由的嵌套
- 也就是說這樣創(chuàng)建的都是平級(jí)的
// 定義一個(gè)賬戶組件
let account = {
template: "#accountTemp",
data() {
return {
}
},
methods: {
},
}
// 定義一個(gè)登陸組件
let login = {
template: "#loginTemp",
data() {
return {
}
},
methods: {
}
}
// 定義一個(gè)注冊(cè)組件
let regist = {
template: "#registTemp",
data() {
return {
}
},
methods: {
},
}
// 定義路由規(guī)則
let router = new VueRouter({
routes: [{
path: "/",
redirect: '/account',
},
{
path: "/account",
component: account
},
{
path: '/login',
component: login
},
{
path: '/regist',
component: regist
}
],
linkActiveClass: 'myActive'
})
// 實(shí)例化一個(gè)vm實(shí)例
let vm = new Vue({
el: "#app2",
methods: {
},
data: {
},
comments: {
account,
login,
regist
},
router: router
})
<div id="app2">
<router-link to="/account">Account</router-link>
<router-link to="/login">登陸</router-link>
<router-link to="/regist">注冊(cè)</router-link>
<router-view></router-view>
</div>
- 現(xiàn)在我們要通過路由匹配規(guī)則中的children屬性來添加子路由
- 在配置children屬性的時(shí)候我們不用在path屬性中加上一個(gè)斜線表示路由荆残,直接加規(guī)則名稱就可以了
- 之后的路由都會(huì)在父路由的基礎(chǔ)上加上子路由作為后綴
- 我們也需要在組件內(nèi)部為router-link跟router-view留出空位奴艾,以便之后的內(nèi)容會(huì)展示在其位置
let router = new VueRouter({
routes: [{
path: "/",
redirect: '/account'
},
{
path: "/account",
component: account,
children: [{
path: 'login',
component: login
}, {
path: 'regist',
component: regist
}]
}
],
linkActiveClass: 'myActive'
})
// 實(shí)例化一個(gè)vm實(shí)例
let vm = new Vue({
el: "#app2",
methods: {
},
data: {
},
comments: {
account,
login,
regist
},
router: router
})
<div id="app2">
<router-link to="/account">Account</router-link>
<router-view></router-view>
</div>
<template id="accountTemp">
<div>
<h1>賬戶組件</h1>
<router-link to="/account/login">登陸</router-link>
<router-link to="/account/regist">注冊(cè)</router-link>
<router-view></router-view>
</div>
</template>
7. 使用命名視圖實(shí)現(xiàn)經(jīng)典布局
- 我們發(fā)現(xiàn)之前我們使用的內(nèi)容均為一個(gè)頁面上面只顯示一個(gè)組件,但是實(shí)際開發(fā)中一個(gè)頁面會(huì)有很多組件
- 但是要知道我們所學(xué)的路由匹配規(guī)則中component只允許放一個(gè)內(nèi)容
- 因此對(duì)component的操作就顯得尤為重要内斯,因此我們把我們的component升級(jí)為了components蕴潦,這樣我們就可以同時(shí)存放多個(gè)組件了
- 但是這樣一想又來了一個(gè)問題,那就是怎么組織這些組件的位置俘闯,
- 因此我們?cè)趓outer-view的基礎(chǔ)上對(duì)他的name屬性進(jìn)行了改造潭苞,我們可以把我們想要展示的組件指定一個(gè)屬性,并把這個(gè)屬性添加到name的參數(shù)里面真朗,這樣就可以完成我們的命名視圖了
- 在components中有一個(gè)特殊的屬性此疹,那就是default屬性了,這個(gè)屬性對(duì)應(yīng)的組件應(yīng)當(dāng)是只要又沒有帶name屬性的router-view都要去展示的組件遮婶,下面將給出實(shí)現(xiàn)源碼
// 定義頭部組件
let header = {
template: "#headerTemp",
data() {
return {
}
},
methods: {
},
}
// 定義左側(cè)組件
let leftPart = {
template: "#leftTemp",
data() {
return {
}
},
methods: {
}
}
// 定義右側(cè)組件
let rightPart = {
template: "#rightTemp",
data() {
return {
}
},
methods: {
},
}
// 定義路由規(guī)則
let router = new VueRouter({
routes: [{
path: "/",
components: {
default: header,
left: leftPart,
right: rightPart
}
}
],
linkActiveClass: 'myActive'
})
// 實(shí)例化一個(gè)vm實(shí)例
let vm = new Vue({
el: "#app2",
methods: {
},
data: {
},
comments: {
header,
leftPart,
rightPart
},
router: router
})
<div id="app2">
<router-view></router-view>
<router-view name="left"></router-view>
<router-view name="right"></router-view>
</div>
<template id="leftTemp">
<div>
<h1>左邊</h1>
</div>
</template>
<template id="rightTemp">
<div>
<h1>右邊</h1>
</div>
</template>
<template id="headerTemp">
<div>
<h1>頭部</h1>
</div>
</template>
- 之后通過對(duì)他們樣式的控制可以完成經(jīng)典視圖的布局