VueRouter--路由
????這里的路由是SPA(單頁(yè)應(yīng)用)的路徑管理器公黑。再通俗的說(shuō)室梅,vue-router就是WebApp的鏈接路徑管理系統(tǒng)矗愧。
????vue-router是Vue.js官方的路由插件肠虽,它和vue.js是深度集成的笤妙,適合用于構(gòu)建單頁(yè)面應(yīng)用。vue的單頁(yè)面應(yīng)用是基于路由和組件的症见,路由用于設(shè)定訪問(wèn)路徑堪置,并將路徑和組件映射起來(lái)。傳統(tǒng)的頁(yè)面應(yīng)用茄唐,是用一些超鏈接來(lái)實(shí)現(xiàn)頁(yè)面切換和跳轉(zhuǎn)的息裸。在vue-router單頁(yè)面應(yīng)用中,則是路徑之間的切換沪编,也就是組件的切換呼盆。路由模塊的本質(zhì) 就是建立起url和頁(yè)面之間的映射關(guān)系。
????至于為什么不能用a標(biāo)簽蚁廓?這是因?yàn)橛肰ue做的都是單頁(yè)應(yīng)用(當(dāng)你的項(xiàng)目準(zhǔn)備打包時(shí)访圃,運(yùn)行npm run build時(shí),就會(huì)生成dist文件夾相嵌,這里面只有靜態(tài)資源和一個(gè)index.html頁(yè)面)腿时,所以你寫的<a></a>
標(biāo)簽是不起作用的况脆,你必須使用vue-router來(lái)進(jìn)行管理。
一批糟、vue-router實(shí)現(xiàn)原理:
????SPA(single page application):單一頁(yè)面應(yīng)用程序格了,只有一個(gè)完整的頁(yè)面;它在加載頁(yè)面時(shí)徽鼎,不會(huì)加載整個(gè)頁(yè)面盛末,而是只更新某個(gè)指定的容器中內(nèi)容。單頁(yè)面應(yīng)用(SPA)的核心之一是: 更新視圖而不重新請(qǐng)求頁(yè)面;vue-router在實(shí)現(xiàn)單頁(yè)面前端路由時(shí)否淤,提供了兩種方式:Hash模式和History模式悄但;根據(jù)mode參數(shù)(mode:'hash')來(lái)決定采用哪一種方式。
1石抡、Hash模式:
????vue-router 默認(rèn) hash 模式 —— 使用 URL 的 hash 來(lái)模擬一個(gè)完整的 URL檐嚣,于是當(dāng) URL 改變時(shí),頁(yè)面不會(huì)重新加載汁雷。 hash(#)是URL 的錨點(diǎn)净嘀,代表的是網(wǎng)頁(yè)中的一個(gè)位置,單單改變#后的部分侠讯,瀏覽器只會(huì)滾動(dòng)到相應(yīng)位置,不會(huì)重新加載網(wǎng)頁(yè)暑刃,也就是說(shuō)hash 出現(xiàn)在 URL 中厢漩,但不會(huì)被包含在 http 請(qǐng)求中,對(duì)后端完全沒(méi)有影響岩臣,因此改變 hash 不會(huì)重新加載頁(yè)面溜嗜;同時(shí)每一次改變#后的部分,都會(huì)在瀏覽器的訪問(wèn)歷史中增加一個(gè)記錄架谎,使用”后退”按鈕炸宵,就可以回到上一個(gè)位置;所以說(shuō)Hash模式通過(guò)錨點(diǎn)值的改變谷扣,根據(jù)不同的值土全,渲染指定DOM位置的不同數(shù)據(jù)。hash 模式的原理是 onhashchange 事件(監(jiān)測(cè)hash值變化)会涎,可以在 window 對(duì)象上監(jiān)聽這個(gè)事件裹匙。
1、Histoey模式:
????由于hash模式會(huì)在url中自帶#末秃,如果不想要很丑的 hash概页,我們可以用路由的 history 模式,只需要在配置路由規(guī)則時(shí)练慕,加入"mode: 'history'",這種模式充分利用了html5 history interface 中新增的 pushState() 和 replaceState() 方法惰匙。這兩個(gè)方法應(yīng)用于瀏覽器記錄棧技掏,在當(dāng)前已有的 back、forward项鬼、go 基礎(chǔ)之上哑梳,它們提供了對(duì)歷史記錄修改的功能。只是當(dāng)它們執(zhí)行修改時(shí)秃臣,雖然改變了當(dāng)前的 URL 涧衙,但瀏覽器不會(huì)立即向后端發(fā)送請(qǐng)求。
????當(dāng)你使用 history 模式時(shí)奥此,URL 就像正常的 url弧哎,例如 http://yoursite.com/user/id,比較好看稚虎!
不過(guò)這種模式要玩好撤嫩,還需要后臺(tái)配置支持。因?yàn)槲覀兊膽?yīng)用是個(gè)單頁(yè)客戶端應(yīng)用蠢终,如果后臺(tái)沒(méi)有正確的配置序攘,當(dāng)用戶在瀏覽器直接訪問(wèn) http://oursite.com/user/id 就會(huì)返回 404,這就不好看了寻拂。
所以呢程奠,你要在服務(wù)端增加一個(gè)覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態(tài)資源,則應(yīng)該返回同一個(gè) index.html 頁(yè)面祭钉,這個(gè)頁(yè)面就是你 app 依賴的頁(yè)面瞄沙。
{path: "*", redirect: "/"}]
//此處就設(shè)置如果URL輸入錯(cuò)誤或者是URL 匹配不到任何靜態(tài)資源,就自動(dòng)跳到到Home頁(yè)面
二慌核、vue-router使用
1距境、安裝路由
npm istall vue-router --save
2、在src/router/inde.js文件中引入垮卓、使用路由
import VueRouter from 'vue-router' //引入路由
Vue.use(VueRouter) 使用路由
3垫桂、在src/main.js文件中引入路由配置文件index.js文件,并將路由對(duì)象傳遞給vue實(shí)例
import router from './router' //引入路由配置文件
Vue.use(VueRouter) 使用路由
new Vue({
el: '#app',
router, //傳遞路由對(duì)象給vue實(shí)例
render: h => h(App)
})
4粟按、在src/router/inde.js配置路由
import Index from './路徑/Index' //引入組件
const router = new VueRouter({
mode:'history', //history模式诬滩,可以去除URL里面的hash符號(hào)(#)
routes:[ //注冊(cè)組件路由,
{
path:'/', //path設(shè)置路徑钾怔,'/'表示根路徑
conponent:Index, //設(shè)置的路徑對(duì)應(yīng)的組件名
name:'index' //組件引用名
}
]
})
5碱呼、在app.vue中留坑<router-view></router-view>
,Index.vue的內(nèi)容就會(huì)展示到router-view這個(gè)容器里面
//app.vue中
<template>
<div>
<!-- 留坑,非常重要 -->
<router-view></router-view>
</div>
</template>
三宗侦、路由跳轉(zhuǎn)
[一]愚臀、<router-link>基本屬性
<router-link to="" tag="">主頁(yè)</router-link>
(1)to屬性表示綁定地址。to="/"
(2):to="",綁定動(dòng)態(tài)路由矾利,與data(){}中的變量進(jìn)行綁定--詳見下文[三]姑裂、動(dòng)態(tài)路由馋袜。
綁定路由表中的name屬性。:to="{name:路由表中name值}"
(3)tag屬性表示以什么標(biāo)簽名顯示舶斧,默認(rèn)以a標(biāo)簽顯示欣鳖;tag=div表示將該標(biāo)簽以div呈現(xiàn)
(4)children:[],子路由在這里面配置,children:[{path:'/',component:xxx,name:xxx,cildren:[三級(jí)路由]},....]
[二]茴厉、路由跳轉(zhuǎn)
1泽台、跳轉(zhuǎn)到上一次瀏覽的頁(yè)面--this.$router.go(-1);
<template>
<div class="container">
<h1>home</h1>
<button @click="goToMenu" class="btn btn-success">just do it</button>
</div>
</template>
<script>
export default {
name: "Home",
methods:{
goToMenu(){
//跳轉(zhuǎn)到上一次瀏覽的頁(yè)面
this.$router.go(-1);
}
}
}
</script>
2、跳轉(zhuǎn)到指定的頁(yè)面--this.$router.replace('/about')
<template>
<div class="container">
<h1>home</h1>
<button @click="goToMenu" class="btn btn-success">just do it</button>
</div>
</template>
<script>
export default {
name: "Home",
methods:{
goToMenu(){
//指定跳轉(zhuǎn)
this.$router.replace('/about')
}
}
}
</script>
3矾缓、跳轉(zhuǎn)到指定路由的名字下--this.$router.replace({name:'nameValue'})
在router/index.js文件下怀酷,對(duì)Menu.vue組件進(jìn)行name賦值
{
path:'/menu',
component:Menu,
name:'menuLink'
},
在Home.vue文件中
<template>
<div class="container">
<h1>home</h1>
<button @click="goToMenu" class="btn btn-success">just do it</button>
</div>
</template>
<script>
export default {
name: "Home",
methods:{
goToMenu(){
//跳轉(zhuǎn)到指定路由的名字
this.$router.replace({name:'menuLink'})
}
}
}
</script>
4、通過(guò)this.$router.push()地址嗜闻,或者name進(jìn)行跳轉(zhuǎn)
- 開發(fā)中這種方法最常用
<template>
<div class="container">
<h1>home</h1>
<button @click="goToMenu" class="btn btn-success">just do it</button>
</div>
</template>
<script>
export default {
name: "Home",
methods:{
goToMenu(){
//push地址跳轉(zhuǎn)
this.$router.push('/menu')
//或者是通過(guò)name屬性
//this.$router.push({name:'menuLink'})
}
}
}
</script>
[三]蜕依、動(dòng)態(tài)路由
動(dòng)態(tài)路由是將:to屬性的值設(shè)置為data中的變量(:to="routerDemo"),將具體的路由地址賦值給變量
<li><router-link :to="homeLink">主頁(yè)</router-link></li>
export default {
name: "Header",
data(){
return{
homeLink:'/'
}
}
}
</script>
[四]琉雳、以導(dǎo)航欄的實(shí)現(xiàn)來(lái)理解
此導(dǎo)航欄只使用了bootstrapcss樣式样眠,在index.html中插入
<link rel="stylesheet" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
1、創(chuàng)建主頁(yè)(Home)翠肘、菜單(OrderingGuide)檐束、管理(Admin)、關(guān)于我們(about/About)束倍、登錄(Login)厢塘、注冊(cè)(Register)組件
<!-- home組件,其余組件略過(guò)-->
<template>
<h1>home</h1>
</template>
<script>
export default {
name: "Home"
}
</script>
2肌幽、在src/router/index.js中配置路由
import Home from './components/Home'
import Menu from './components/Menu'
import Admin from './components/Admin'
import About from './components/about/About'
import Login from './components/Login'
import Register from './components/Register'
const router = new VueRouter({
mode:'history', //history模式,可以去除URL里面的hash符號(hào)(#)
routes:[ //注冊(cè)組件路由抓半,
{
path:'/',
component:Home,
},{
path:'/menu',
component:Menu
},{
path:'/admin',
component:Admin
},{
path:'/about',
component:About,
},{
path:'/login',
component:Login
},{
path:'/register',
component:Register
}
]
})
3喂急、新建一個(gè)header.vue組件,用于寫頂部導(dǎo)航欄
<template>
<header>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<!-- svg矢量圖logo-->
<a class="py-2" href="#" aria-label="Product">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="d-block mx-auto" role="img" viewBox="0 0 24 24" focusable="false"><title>Product</title><circle cx="12" cy="12" r="10"></circle><path d="M14.31 8l5.74 9.94M9.69 8h11.48M7.38 12l5.74-9.94M9.69 16L3.95 6.06M14.31 16H2.83m13.79-4l-5.74 9.94"></path></svg>
</a>
<a href="/" class="navbar-brand">Pizza點(diǎn)餐系統(tǒng)</a>
<!-- 頂部 左側(cè)-->
<ul class="navbar-nav">
<!-- navbar-nav去除li前面的小點(diǎn)-->
<li><router-link to="/" class="nav-link">主頁(yè)</router-link></li>
<li><router-link to="/menu" class="nav-link">菜單</router-link></li>
<li><router-link to="/admin" class="nav-link">管理</router-link></li>
<li><router-link to="/about" class="nav-link">關(guān)于我們</router-link></li>
</ul>
<!-- 頂部-右側(cè)-->
<ul class="navbar-nav ml-auto">
<!-- ml-auto實(shí)現(xiàn)兩個(gè)li在頂部最右側(cè)-->
<li><router-link to="/login" class="nav-link">登錄</router-link></li>
<li><router-link to="/register" class="nav-link">注冊(cè)</router-link></li>
</ul>
</nav>
</header>
</template>
<script>
export default {
name: "Header"
}
</script>
4笛求、在app.vue中引入導(dǎo)航欄廊移,以及為導(dǎo)航欄的導(dǎo)航組件(主頁(yè)、菜單探入、管理等)留坑
<template>
<div id="app">
<!-- header導(dǎo)航欄組件將在這展示-->
<div class="container">
<app-header></app-header>
</div>
<!-- 為導(dǎo)航欄的導(dǎo)航組件(主頁(yè)狡孔、菜單、管理等)留坑-->
<div class="container">
<router-view></router-view>
</div>
</div>
</template>
<script>
import Header from "./components/Header";
export default {
name: 'app',
components:{
//屬性名:組件名
//屬性名駝峰式命名的話 蜂嗽,ES6會(huì)自動(dòng)解析為app-header;如果屬性名命名為app-header的話苗膝,必須使用引號(hào)
appHeader:Header,
}
}
</script>
[五]、路由嵌套
1植旧、在router/index.js文件中配置一級(jí)辱揭、二級(jí)离唐、三級(jí)路由
//一級(jí)路由
import About from './components/about/About'
//二級(jí)路由
import Contact from "./components/about/Contact";
import Delivery from "./components/about/Delivery";
import History from "./components/about/History";
import OrderingGuide from "./components/about/OrderingGuide";
//三級(jí)路由
import Person from "./components/about/contact/Person";
import Phone from "./components/about/contact/Phone";
{
path:'/about',
component:About,
name:'aboutLink',
redirect:'/about/history',//默認(rèn)顯示
children:[
{
path:'/about/contact',
name:'contactLink',
component:Contact,
children:[
{
path:'/phone',
name:'phoneNumber',
component:Phone
},{
path:'/person',
name:'person',
component:Person
},
]
},{
path:'/about/delivery',
name:'deliveryLink',
component:Delivery
},{
path:'/about/history',
name:'historyLink',
component:History
},{
path:'/about/orderingGuide',
name:'orderingGuideLink',
component:OrderingGuide
},
]
},
2、一級(jí)路由的vue文件
導(dǎo)航欄header組件在app.vue中使用
<template>
<div id="app">
<div class="container">
<!--使用header組件-->
<app-header></app-header>
</div>
<div class="container">
<!--header上的每一個(gè)按鈕對(duì)應(yīng)的vue文件內(nèi)容將展示在此-->
<router-view></router-view>
</div>
</div>
</template>
<script>
import Header from "./components/Header";
export default {
name: 'app',
components:{
//屬性名:組件名
//屬性名駝峰式命名的話 问窃,ES6會(huì)自動(dòng)解析為app-header;如果屬性名命名為app-header的話亥鬓,必須使用引號(hào)
appHeader:Header,//引用header組件
},
}
</script>
header組件內(nèi)容
<template>
<header>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<!-- 頂部 左側(cè)-->
<ul class="navbar-nav">
<!-- navbar-nav去除li前面的小點(diǎn)-->
<li><router-link to="/about" class="nav-link">關(guān)于我們</router-link></li>
</ul>
<!-- 頂部-右側(cè)-->
</nav>
</header>
</template>
3、二級(jí)路由的vue文件
<template>
<div>
<div class="row mb-5">
<div class="col-4">
<!-- 導(dǎo)航router-link-->
<div class="list-group mb-5">
<router-link tag="li" class="nav-link" :to="{name:'historyLink'}">
<a class="list-group-item list-group-item-action">歷史訂單</a>
</router-link>
<router-link tag="li" class="nav-link" :to="{name:'contactLink'}">
<a class="list-group-item list-group-item-action">聯(lián)系我們</a>
</router-link>
<router-link tag="li" class="nav-link" :to="{name:'orderingGuideLink'}">
<a class="list-group-item list-group-item-action">點(diǎn)餐</a>
</router-link>
<router-link tag="li" class="nav-link" :to="{name:'deliveryLink'}">
<a class="list-group-item list-group-item-action">快遞信息</a>
</router-link>
</div>
</div>
<div class="col-8">
<!-- 留坑域庇,三級(jí)路由的vue文件內(nèi)容將展示在此嵌戈。about路由下的兩個(gè)子路由內(nèi)容,點(diǎn)擊后將展示在此-->
<router-view></router-view>
</div>
</div>
</div>
</template>
[六]听皿、router-view復(fù)用熟呛,通過(guò)路由的方式重復(fù)使用同一個(gè)組件
1、在需要復(fù)用的路由下添加conponents屬性
//src/router/index.js
{
path:'/',
component:Home,
name:'homeLink',
components:{ //需要復(fù)用的組件
'orderingGuide':OrderingGuide,
'delivery':Delivery,
'history':History
}
},
2写穴、在需要復(fù)用組件的vue文件使用router-view-----未完待續(xù)
<!-- router-view復(fù)用-->
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-4">
<router-view name="orderingGuide"></router-view>
</div>
<div class="col-sm-12 col-md-4">
<router-view name="delivery"></router-view>
</div>
<div class="col-sm-12 col-md-4">
<router-view name="history"></router-view>
</div>
</div>
</div>
</div>
四惰拱、路由守衛(wèi)
1、全局守衛(wèi)
router.beforeEach((to,from,next)=>{
to:路由地址啊送,即將要進(jìn)入的目標(biāo) 路由對(duì)象
from:路由地址偿短,從哪一個(gè)路由離開
next:異步函數(shù),決定展示頁(yè)面
})
// 全局守衛(wèi)
router.beforeEach((to,from,next)=>{
comsole.log(to);
//這里通常是判斷store.getters.isLogin===false來(lái)確定是否登錄
if(to.path == '/login' || to.path == '/register'){
next();
}else{
alert('未登錄')
next('/login')
}
})
2馋没、全局后置鉤子
router.afterEach((to,from)=>{
to:路由地址昔逗,即將要進(jìn)入的目標(biāo) 路由對(duì)象
from:路由地址,從哪一個(gè)路由離開
})
3篷朵、路由獨(dú)享守衛(wèi)
beforeEnter:(to,from,next)=>{
//寫在路由配置里面
}
{
path:'/admin',
component:Admin,
name:'adminLink',
beforeEnter:(to,from,next)=>{
alert('非管理員禁止進(jìn)入');
if(to.path == '/login' || to.path == '/register'){
next();
}else{
alert('未登錄')
next('/login')
}
}
},
4勾怒、組件內(nèi)的守衛(wèi)
beforeRouteEnter (to, from, next) {
// 在渲染該組件的對(duì)應(yīng)路由被 confirm 前調(diào)用
// 不!能声旺!獲取組件實(shí)例 `this`
// 因?yàn)楫?dāng)守衛(wèi)執(zhí)行前笔链,組件實(shí)例還沒(méi)被創(chuàng)建
},
beforeRouteUpdate (to, from, next) {
// 在當(dāng)前路由改變,但是該組件被復(fù)用時(shí)調(diào)用
// 舉例來(lái)說(shuō)腮猖,對(duì)于一個(gè)帶有動(dòng)態(tài)參數(shù)的路徑 /foo/:id鉴扫,在 /foo/1 和 /foo/2 之間跳轉(zhuǎn)的時(shí)候,
// 由于會(huì)渲染同樣的 Foo 組件澈缺,因此組件實(shí)例會(huì)被復(fù)用坪创。而這個(gè)鉤子就會(huì)在這個(gè)情況下被調(diào)用。
// 可以訪問(wèn)組件實(shí)例 `this`
},
beforeRouteLeave (to, from, next) {
// 導(dǎo)航離開該組件的對(duì)應(yīng)路由時(shí)調(diào)用
// 可以訪問(wèn)組件實(shí)例 `this`
}
(1)姐赡、beforeRouteEnter
beforeRouteEnter(to,from,next){
//會(huì)報(bào)錯(cuò)莱预,Cannot read property 'name' of undefined
alert('查看現(xiàn)在能否拿到data內(nèi)的數(shù)據(jù)'+this.name);
}
????beforeRouteEnter 守衛(wèi) 不能 訪問(wèn) this,因?yàn)槭匦l(wèi)在導(dǎo)航確認(rèn)前被調(diào)用项滑,因此即將登場(chǎng)的新組件還沒(méi)被創(chuàng)建依沮。
????不過(guò),你可以通過(guò)傳一個(gè)回調(diào)給 next來(lái)訪問(wèn)組件實(shí)例。在導(dǎo)航被確認(rèn)的時(shí)候執(zhí)行回調(diào)悉抵,并且把組件實(shí)例作為回調(diào)方法的參數(shù)肩狂。
beforeRouteEnter (to, from, next) {
next(vm => {
// 通過(guò) `vm` 訪問(wèn)組件實(shí)例
alert('查看現(xiàn)在能否拿到data內(nèi)的數(shù)據(jù)'+vm.name);
})
}
(2)、beforeRouteUpdate
待續(xù).....
(3)姥饰、beforeRouteLeave
beforeRouteLeave(to,from,next){
alert('查看現(xiàn)在能否拿到data內(nèi)的數(shù)據(jù)'+this.name)
if(confirm('確定離開嗎傻谁??列粪?') == true){
next()
}else{
next(false)
}
}