概述
路由就是对应关系。在前端中的路由指的是 Hash 地址和组件之间的对应关系。
通俗来理解,路由就是帮助我们通过控制 Hash 地址来完成页面中的组件的切换。
SPA 就是单页面网站,在 web 网站中只有一个页面,所有的组件的展示与切换都在这个唯一的页面进行完成,不会发生页面跳转。这种不同组件之间的切换就需要通过前端路由来完成。
Hash 地址在前端中指的是 # 之后的地址,这个地址在转换的时候不会发生页面跳转。如 brokyz.tk/#/header/su… 中 /header/sub 就是 Hash 地址。
前端路由的工作方式:
- 用户点击了页面上的路由链接。
- 导致 URL 地址栏中的 Hash 值发生变化。
- 前端路由监听到了 Hash 值的变化。
- 前端路由把当前 Hash 值对应的组件渲染到页面当中。
使用动态组件模拟路由
<template>
<div class="imicontainer">
<h1>imiRouter</h1>
<a href="#/about">about</a>
<a href="#/home">home</a>
<a href="#/mine">mine</a>
<component :is="comName"></component>
</div>
</template>
<script>
import about from "@/components/about.vue";
import home from "@/components/home.vue";
import mine from "@/components/mine.vue";
export default {
name: "imiRouter",
data() {
return {
comName: "home",
};
},
components: {
about,
home,
mine,
},
created(){
window.onhashchange = () => {
switch(location.hash) {
case '#/home':
this.comName = 'home'
break
case '#/about':
this.comName = 'about'
break
case '#/mine':
this.comName = 'mine'
break
}
}
}
};
</script>
<style scoped>
a {
padding: 0 10px;
}
</style>
vue-router
概述
vue-router 是 vue.js 官方给出的路由解决方案。他只能结合 vue 项目进行使用,能够轻松的管理 SPA 项目中组件的切换。
官方文档:router.vuejs.prg/zh/
vue-router 安装
在 vue2 中安装需要安装 vue-router3 和其一下的版本,因为更新的版本对 vue2 不支持。需要到 vue3 才可以使用。
所以需要安装时一定要带上版本号。
npm i vue-router@3 -S
创建路由模块
在 src 源代码目录下,新建 router/index.js 路由模块,并初始化如下的代码:
// 1. 导入 Vue 和 VueRouter 的包
import Vue from 'vue'
import VueRouter from 'vue-router'
// 2. 通过 Vue.use() 函数,把 VueRouter 安装为 Vue 的组件
Vue.use(VueRouter)
// 3. 创建路由的实例对象
const router = new VueRouter()
// 4. 向外共享路由的实例对象
export default router
导入并挂载路由模块
在 src/main.js 入口文件中,导入并挂载路由模块。
import Vue from 'vue'
import App from './App.vue'
// 导入路由模块
import router from '@/router'
// 浏览器控制台提示信息
Vue.config.productionTip = false
new Vue({
render: h => h(App),
// 可以省略为 router
router:router
}).$mount('#app')
声明路由链接和占位符
在 src/App.vue 组件中,使用 vue-router 提供的 <router-link> 和 <router-view> 声明路由链接和占位符。
<template>
<div id="app">
<h1>vue-router</h1>
<router-link to="/home">home</router-link>
<router-link to="/mine">mine</router-link>
<router-link to="/about">about</router-link>
<hr>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "app",
}
</script>
<style lang="less">
#app {
a {
padding: 0 10px;
}
}
</style>
声明路由的匹配规则
在 src/router/index.js 路由模块中,通过 routes 数组声明路由的匹配机制。
// 1. 导入 Vue 和 VueRouter 的包
import Vue from 'vue'
import VueRouter from 'vue-router'
// 2. 通过 Vue.use() 函数,把 VueRouter 安装为 Vue 的组件
Vue.use(VueRouter)
// 3. 创建路由的实例对象
import about from "@/components/about.vue";
import home from "@/components/home.vue";
import mine from "@/components/mine.vue";
const router = new VueRouter({
routes: [
{path: '/home', component: home},
{path: '/mine', component: mine},
{path: '/about', component: about},
]
})
// 4. 向外共享路由的实例对象
export default router
路由重定向
路由重定向指的是:用户在访问地址 A 的时候,强制用户跳转到地址 C ,从而展示特定的组件页面。
通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由的重定向。
const router = new VueRouter({
routes: [
// 当用户访问 / 的时候,通过重定向跳转到 /home 对应的路由规则
{path: '/', redirect: '/home'},
{path: '/home', component: home},
{path: '/mine', component: mine},
{path: '/about', component: about},
]
})
嵌套路由
通过路由实现组件的嵌套展示。
<template>
<div id="home">
<h4>home</h4>
<router-link to="/home/tab1">tab1</router-link>
<router-link to="/home/tab2">tab2</router-link>
<router-view></router-view>
</div>
</template>
import about from "@/components/about.vue";
import home from "@/components/home.vue";
import mine from "@/components/mine.vue";
import tab1 from "@/components/tab1.vue";
import tab2 from "@/components/tab2.vue";
const router = new VueRouter({
routes: [
{ path: '/', redirect: '/home' },
{
path: '/home',
component: home,
// 默认子路由跳转到tab1
redirect: '/home/tab1',
children: [
{ path: 'tab1', component: tab1 },
{ path: 'tab2', component: tab2 }
]
},
{ path: '/mine', component: mine },
{ path: '/about', component: about },
]
})
动态路由
如果不同的路由地址,同时使用同一个组件,不用一个个绑定路由,可以使用动态路由。
<template>
<div id="about">
<h4>about</h4>
<router-link to="/about/id-000001">content1</router-link>
<router-link to="/about/id-000002">content2</router-link>
<router-link to="/about/id-000003">content3</router-link>
<router-view></router-view>
</div>
</template>
const router = new VueRouter({
routes: [
{ path: '/', redirect: '/home' },
{
path: '/home',
component: home,
redirect: '/home/tab1',
children: [
{ path: 'tab1', component: tab1 },
{ path: 'tab2', component: tab2 }
]
},
{ path: '/mine', component: mine },
{
path: '/about',
component: about,
// 可以使用如下的动态路由
// children: [
// { path: 'id-000001', component: tab1 },
// { path: 'id-000002', component: tab1 },
// { path: 'id-000003', component: tab1 }
// ]
children: [
{ path: ':id', component: tab1}
]
},
]
})
动态路由传递路由参数
在路由渲染出的组件中,可以使用 this.$route.params 来访问获取到的动态匹配值
<template>
<div id="tab1">
<h4>tab1</h4>
<P>动态路由参数 this.$route.params.id :{{ this.$route.params.id }}</P>
</div>
</template>
也可以在路由参数中,开启 props 传参
{
path: '/about',
component: about,
children: [
{ path: ':id', component: tab1, props: true }
]
}
<template>
<div id="tab1">
<h4>tab1</h4>
<P>动态路由参数 props 接收 id:{{ id }}</P>
</div>
</template>
<script>
export default {
name: "tab1",
props: ['id']
};
</script>
拓展 this.$route 路由对象
$route: Object
fullPath: "/about/id-000003?id=4&test=1"
hash: ""
matched: (2) [{…}, {…}]
meta: {}
name: undefined
params: {id: 'id-000003'}
path: "/about/id-000003"
query: {id: '4', test: '1'}
[[Prototype]]: Object
- fullPath:完整的路由地址。
- path:不带 query 的路由地址。
- params:动态路由参数。
- query:路由中的 query 值。
注意:this.$route 是路由参数对象,this.$router 是路由导航对象。
编程式导航 API
在浏览器中,点击链接实现导航的方式,叫做声明式导航。例如:普通网页中点击 <a> 链接、vue 项目中点击 <router-link> 都属于声明式导航。
在浏览器中,调用 API 方法实现导航的方式,叫做编程式导航。例如:普通网页中调用 location.href 跳转到新页面的方式,属于编程式导航。
vue-router 提供了许多编程式导航的 API,其中最常用的导航 API 分别是:
this.$router.push('hash 地址'): 跳转到指定 hash 地址,并增加一条历史记录。
this.$router.replace('hash 地址'):跳转到指定的 hash 地址,并替换掉当前的历史记录。
-
this.$router.go(数值 n):实现导航历史前进、后退。- $router.back():在历史记录中,后退到上一个页面。
- $router.forward():在历史记录中,前进到下一个页面。
导航守卫
导航守卫可以控制路由的访问权限。
全局前置守卫
每次发生路由的导航跳转时,都会触发全局前置守卫。因此,在全局前置守卫中,程序员可以对每个路由进行访问权限的控制。
const router = new VueRouter({...})
// 调用 beforeEach 方法可以声明全局前置守卫
// 每次发生路由导航跳转时,都会自动触发回调函数
router.beforeEach((to, from, next)=>{
// to 是要访问的路由信息对象
// from 是要离开的路由信息对象
// next 是一个函数,调用 next() 表示放行,允许这次路由导航。
})
next 函数的三种调用方式:
当前用户拥有后台主页的访问权限,直接放行:next()
当前用户没有后台主页的访问权限,强制其跳转到登录页面:next('/login')
当前用户没有后台主页的访问权限,不允许跳转到后台主页:next(false)
router.beforeEach((to, from, next) => {
if (to.path === '/main') {
const token = localStorage.getItem('token')
if (token) {
next() // 访问的是 main 并且有 token 值,放行
} else {
next('/login') // 访问的是 main 但是没有 token,跳转到登陆页面
}
} else {
next() // 访问的不是 main,直接放行
}
})