vue-router 是 Vue.js 官方提供的路由管理器,它有两种路由模式:hash模式和history模式。
hash模式:vue-router 默认的模式是hash模式,hash模式背后的原理是onhashchange事件。hash模式的特点在于hash出现在url中,但是不会被包括在HTTP请求中,对后端没有影响,不会重新加载页面。hash模式的url中会带有一个#符号,例如:http://www.abc.com/#/hello,hash值为#/hello。hash模式对于浏览器的兼容性比较好,也是SPA单页面应用的标配。
history模式:history模式利用了HTML5 History Interface中新增的pushState()和replaceState()方法(需要特定浏览器支持)。history模式的url相对于hash模式而言,更加美观。history模式使用浏览器的history API来管理路由状态,而不是依赖于URL中的哈希。在history模式下,URL看起来更加整洁,没有#符号。例如,http://example.com/user/profile。history模式可以在不刷新整个页面的情况下,通过改变URL来切换页面,实现更加流畅的用户体验。但是history模式需要后台配置支持,如果后台没有正确配置,访问时会返回404。
vue-router 传参有两种方式:一种是路由参数,通过定义动态路由传递参数;另一种是通过query来传递参数。vue-router 中route和router的区别在于:route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name、path、params、query等。router是VueRouter的一个对象,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,这个对象中是一个全局的对象,包含了所有的路由包含了许多关键的对象和属性。例如history对象$router.push({path:’ /path’}),本质是向history栈中添加一个路由,在我们看来是切换路由,但本质是在添加一个history记录。
导航解析流程:
-
导航被触发:用户点击链接、手动输入 URL 或通过代码进行路由跳转等操作,触发导航。
-
在失活的组件里调用离开守卫(
beforeRouteLeave):如果当前有组件即将失活,会调用该组件内的beforeRouteLeave守卫。 -
调用全局的前置守卫(
beforeEach):执行在路由实例对象中注册的全局前置守卫函数。 -
在重用的组件里调用
beforeRouteUpdate守卫(2.2+):如果是在具有动态参数的路由中,且组件被复用时,会调用该守卫。 -
在路由配置里调用路由独享的守卫(
beforeEnter):针对当前路由配置中定义的beforeEnter守卫进行调用。 -
解析异步路由组件:处理异步加载的路由组件。
-
在被激活的组件里调用
beforeRouteEnter:执行激活组件中的beforeRouteEnter守卫。 -
调用全局的解析守卫(
beforeResolve,2.5+):触发全局解析守卫函数。 -
导航被确认:完成所有守卫的检查和处理后,确认导航。
-
调用全局的后置钩子(
afterEach):执行全局后置钩子函数,但该钩子不会接受next函数,也不会改变导航本身。 -
触发 DOM 更新:更新页面的 DOM 结构以显示目标组件。
-
用创建好的实例调用
beforeRouteEnter守卫中传给next的回调函数:如果在beforeRouteEnter守卫中通过next传递了回调函数,此时会使用创建好的组件实例来调用该回调函数。
在这个流程中,导航守卫起到了关键的作用,它们可以用于权限控制、路由跳转前的准备工作、处理路由参数变化等。每个守卫函数都接收三个参数:to(即将要进入的目标路由对象)、from(当前导航正要离开的路由)、next(一个必须调用的函数,用于决定是否继续导航或进行其他操作)。
以下是一个示例,展示了如何设置导航守卫:
// 全局前置守卫(在路由的 index.js 页面设置)
router.beforeEach((to, from, next) => {
// 进行一些全局的操作,如权限控制等
if (满足某些条件) {
next(); // 继续进行导航
} else {
// 中断导航或跳转到其他页面
next('/login');
}
});
// 路由独享的守卫(在路由配置项中定义)
{
path: '/test',
component: testComponent,
beforeEnter: (to, from, next) => {
// 进行路由独享的操作
next();
}
}
// 组件内的守卫(在组件中定义)
export default {
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
next(vm => {
// 通过 vm 访问组件实例
});
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变但组件被复用时调用
next();
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
const answer = window.confirm('是否确认离开当前页面');
if (answer) {
next();
} else {
next(false);
}
}
};