一、前端路由
什么是前端路由?简单地说,前端路由是一种根据url来渲染前端组件的技术。
前端路由应用于什么场景?多页面的场景,在多页面的场景下,相对于后端路由,前端路由由于可以实现无刷新的效果,用户体验更好。
比如,当我们的应用有两个页面,home主页,和user用户页面时候,我们希望https://my.domain.com/home访问到主页的内容,https://my.domain.com/user访问用户页面,我们就可以使用前端路由来实现。
使用前端路由,每个访问路径会对应一个组件,这个组件我们页称为页面。
二、Vue Router
注意本文中示例vue-router使用的版本是4
1. 路由配置
使用前端路由技术开发应用时候,我们希望指定url的路径与组件之间的对应关系,即当访问某个url时候,渲染哪个组件。
这是通过Vue Router提供的API:createRouter方法来实现的。具体使用为以下步骤:
- 提供路由配置并传入到createRouter方法中
- 在组件中通过
指定组件渲染的位置,当路径匹配上时候,组件会替换掉 标签。
// main.js
import { createApp } from 'vue';
import {createRouter, createWebHistory} from 'vue-router';
import routerConfig from './route.config';
import App from './App';
const router = createRouter({
history: createWebHistory(),
routes: routerConfig
});
createApp(App).use(router).mount('#app')
// route.config.js
import Home from './pages/home';
import User from './pages/user';
export default [
{
path: '/home',
component: Home
},
{
path: '/user',
component: User
}
];
// App.vue
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
export default {};
</script>
上面实例代码展示了基本的路由配置,当访问localhost:8080/home时候,会渲染Home组件,当访问localhost:8080/user时候会渲染user组件。
当在全局注入了router(createApp(App).use(router))之后,在组件中可以通过this.$route来访问路由对象。
2. 动态路由匹配
有时候我们需要动态的路由,即路径中存在动态的字符,这时候可以通过Vue Router支持的动态路由语法来匹配。
路由配置:
{
// http://localhost:8080/user/123
path: '/user/:id',
component: User
}
User组件:
<template>
<div>user: {{$route.params.id}}</div>
</template>
<script>
export default {};
</script>
当访问http://localhost:8080/user/123时候,匹配上了路由’/user/:id’,其中123对应id。因此会渲染component声明的组件:User,在User里面可以通过this.$route访问路由对象,$route.params是动态路由匹配到的参数,所以模板中的{{$route.params.id}}值为123。
3. 导航链接和编程式导航
我们已经知道了如何通过配置路由来让访问路径和组件对应。那么在应用内如何处理路由跳转呢?即我们想实现点击某个链接跳转页面,应该怎么做呢?
有两种方式,导航链接和编程式导航。
导航链接即使用Vue Router提供的组件:
<router-link to="/home">进入home页面</router-link>
上面的代码会在页面展示一个“进入home页面”的超链,点击之后跳转到home页面。它的行为和原生的a标签并不一样,它不会真正刷新浏览器,而只是渲染home组件。
编程式导航是通过js代码来实现路由跳转
<button @click="gotoHome">点击进入home页面</button>
{
methods: {
gotoHome() {
this.$router.push('/home');
}
}
};
编程式导航更加灵活,比如当跳转不是点击触发的时候,就需要用编程式导航来实现。
4. 重定向和别名
重定向:如果我们希望访问一个路径时候,自动跳转到另一个路径,那么就需要Vue Router提供的重定向的能力。
{
path: '/',
redirect: '/home'
}
这样配置声明了访问根路径时候重定向到’/home’。当访问http://localhost:8080时候,就会自动跳转到[http://localhost:8080](http://localhost:8080)/home了。
别名:设置一个路由的别名,可以让不同访问的路径指向同一个组件。
{
path: '/home',
component: Home,
alias: '/main'
},
上面的配置会让我们在访问http://localhost:8080/home和http://localhost:8080/main时候都会渲染Home组件。
5. 嵌套路由
一般一个web应用的路径可能是多级的,比如我们有一个用户列表页面,还有一个用户详情页。那么我们会希望https://my.domain.com/user/list访问用户列表页,https://my.domain.com/user/detail访问的是用户详情页。
对于多级路径,在路由配置时候是嵌套的形式,user是外层路由,而list和detail是里层路由,
对于嵌套路由的配置有2个步骤:
- 配置父路由和子路由,通过children字段声明
- 父路由声明子路由的组件渲染的位置,通过
组件来实现。
例如我们想在上面’/user/:id’动态路由后面增加一个嵌套路由’/user/:id/list’和’/user/:id/detail’,那么首先配置路由
{
path: '/user/:id',
component: User,
children: [
{
path: '/user/:id/list',
component: UserList
},
{
path: '/user/:id/detail',
component: UserDetail
}
]
}
然后在父路由User组件中增加
<template>
<div>user: {{$route.params.id}}</div>
<router-view></router-view>
</template>
<script>
export default {};
</script>
然后访问/user/123/list和/user/123/detail就可以看到能够正常展示了。
这里要注意父路由的
6. 导航守卫
很多情况下我们需要在路由跳转前后做一些处理,例如在跳转到某个路由之前先判断一下用户是否有权限,如果没有权限组不跳转。
导航守卫是Vue Router提供的在路由跳转前后做处理的钩子API。
主要有3中导航守卫:全局守卫,路由独享守卫和组件内守卫
当我们需要在路由跳转时候做一些通用逻辑时候可以使用全局守卫。
import { createApp } from 'vue';
import {createRouter, createWebHistory} from 'vue-router';
import routerConfig from './route.config';
import App from './App';
const router = createRouter({
history: createWebHistory(),
routes: routerConfig
});
// 全局守卫
router.beforeEach((to, from) => {
console.log(`从${from.path} 跳转到 ${to.path}`);
});
createApp(App).use(router).mount('#app')
对于个别路由自己的逻辑可以使用路由独享守卫
{
path: '/user/:id',
component: User,
children: [
{
path: 'list',
component: UserList,
// return false 则不跳转
beforeEnter: () => {
return false
},
},
{
path: 'detail',
component: UserDetail
},
]
}
在组件中也可以声明相应地钩子来处理跳转逻辑
// UserList.vue
<template>
<div>user-list</div>
</template>
<script>
export default {
beforeRouteEnter() {
return false;
}
};
</script>
7. 两种历史记录模式
两种历史记录模式的使用
前端路由有两种模式,HTML5和hash,默认是hash模式。这两种模式本质是不同的底层浏览器技术,但是上层Vue Router做了统一化的封装,因此在我们开发组件和配置路由时候使用这两种模式的区别并不大:
import {createRouter, createWebHistory, createWebHashHistory} from 'vue-router';
import routerConfig from './route.config';
const router = createRouter({
// createWebHashHistory
history: createWebHistory(),
routes: routerConfig
});
可以看到在使用createRouter创建vue路由时候,可以指定使用HTML5(createWebHistory)还是hash模式(createWebHashHistory)。
比如如果访问home页,hash是这样的http://localhost:8080/#/home,HTML5模式是这样的http://localhost:8080/home
这两种模式有几个主要区别
- HTML5模式的路由没有”#”字符,而是在域名后直接写路径,更加优雅
- 由于#后面的字符不会发给服务器,因此hash路由SEO比较差,且不会在服务器生成日志记录
- HTML5需要服务器在访问不同的路径时候都能fallback到index.html,因此相对麻烦
两种历史记录模式的原理
前端路由的原理关键有2点
- 可以修改url,但不会引起刷新,从而在不刷新的页面的情况下跳转路由。
- 监听url改变,根据url渲染对应组件。
hash模式和history模式的原理都是基于这两点。hash是通过浏览器提供的location
API修改url,通过onhashchange
方法监听hash改变;history通过浏览器提供的history.pushState
或者history.replacestate
修改url,通过popState
事件监听url改变。