一、前端路由
什么是前端路由?简单地说,前端路由是一种根据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.jsimport { 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.jsimport 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/123path: '/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({// createWebHashHistoryhistory: 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是通过浏览器提供的locationAPI修改url,通过onhashchange方法监听hash改变;history通过浏览器提供的history.pushState或者history.replacestate修改url,通过popState事件监听url改变。
