基本概念
路由(Route): Vue Router 使用路由来管理 URL 和组件之间的映射关系。每个路由可以包含一个路径(path)和一个对应的组件(component)。
路由器(Router): Vue Router 的实例,用于管理整个应用的路由。
路由视图(RouterView): 用于显示匹配当前 URL 的组件的容器。通常情况下,一个 Vue 组件中只能包含一个
<router-view>
,它会根据当前 URL 自动切换显示不同的组件。
前端路由与后端路由
后端路由
前端路由
基本使用
import Vue from "vue";
import VueRouter from "vue-router";
// 引入组件
import home from "./home.vue";
import about from "./about.vue";
// 要告诉 vue 使用 vueRouter
Vue.use(VueRouter);
const routes = [
{
path:"/home",
component: home
},
{
path: "/about",
component: about
}
]
var router = new VueRouter({
routes
})
export default router;
路由匹配
动态路由
应用实例:当我们去访问网站并登录成功后,它会显示 欢迎你,+ 你的名字。不同的用户登录, 只是显示“你的名字” 部分不同,其它部分是一样的
//router.js中
/*新增user路径,配置了动态的id*/
{
path: "/user/:id",
component: user
},
//组件中
<router-link to="/user/123">User123</router-link>
嵌套路由
在路由的设计上,首先进入到 home ,然后才能进入到phone, tablet, computer. Phone, tablet, compute 就相当于进入到了home的子元素。所以vue 提供了childrens 属性,它也是一组路由,相当于我们所写的routes。
{
path:"/home",
// 下面这个属性也不少,因为,我们是先进入home页面,才能进入子路由
component: home,
// 子路由
children: [
{
path: "phone",
component: phone
},
{
path: "tablet",
component: tablet
},
{
path: "computer",
component: computer
}
]
},
路由导航
编程式导航
使用 router.push
、router.replace
和 router.go
方法来实现页面的跳转。
// 字符串(路径名称)
router.push('/home')
// 对象
router.push({path: '/home'})
// 命名的路由(传递参数)
router.push({name: 'user', params: {id: 123}})
// 带查询参数, 变成/user?name=zhangsan
router.push({path: '/user', query: {name: 'zhangsan'}})
meta属性
在Vue路由(vue-router)中,meta
是一种用来描述路由元信息的属性。路由元信息是指在路由配置中,可以为每个路由添加一些额外的数据或配置,这些数据或配置可以用来控制路由的行为或在路由之间共享数据。meta
属性就是用来定义这些路由元信息的。
meta 的作用
- 动态设置页面标题:可以在
meta
中指定页面标题,并在路由守卫中动态设置document.title
。 - 权限控制:在
meta
中指定允许访问的角色,实现不同用户角色的权限管理。 - 页面缓存:通过
meta
属性中的某个字段(如keepAlive
)来控制页面是否应该被缓存。 - 页面过渡效果:在
meta
中指定页面过渡效果,并在主组件中使用<transition>
标签来实现。 - 加载指示器:通过
meta
属性控制路由切换时是否显示加载指示器。
具体案例
以下是一个使用 meta
属性的具体案例,展示了如何在Vue路由中配置和使用 meta
来设置页面标题和进行权限控制。
设置页面标题
const routes = [
{
path: '/home',
name: 'Home',
component: () => import('@/views/Home'),
meta: {
title: 'Home Page'
}
},
{
path: '/about',
name: 'About',
component: () => import('@/views/About'),
meta: {
title: 'About Us'
}
}
];
router.beforeEach((to, from, next) => {
if (to.meta.title) {
document.title = to.meta.title;
}
next();
});
在这个案例中,我们为每个路由对象添加了一个 meta
属性,并在其中设置了 title
字段。然后,在全局前置守卫 beforeEach
中,我们检查即将进入的路由的 meta
属性中是否有 title
字段,如果有,则将其设置为页面的标题。
权限控制
const routes = [
{
path: '/admin',
name: 'Admin',
component: () => import('@/views/Admin'),
meta: {
requiresAuth: true,
roles: ['admin']
}
},
{
path: '/user',
name: 'User',
component: () => import('@/views/User'),
meta: {
requiresAuth: true,
roles: ['user', 'admin']
}
}
];
function getUserRole() {
return localStorage.getItem('userRole');
}
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
const userRole = getUserRole();
if (!userRole) {
next({ path: '/login' });
} else if (to.meta.roles && to.meta.roles.indexOf(userRole) === -1) {
next({ path: '/unauthorized' });
} else {
next();
}
} else {
next();
}
});
在这个案例中,我们为每个需要认证的路由设置了 requiresAuth
和 roles
字段。在全局前置守卫中,我们首先检查即将进入的路由是否需要认证(即 requiresAuth
是否为 true
)。如果需要认证,我们再检查用户角色是否匹配。如果不匹配或用户未登录,则重定向到相应的页面(如登录页面或未授权页面)。
声明式导航
使用 <router-link>
组件来生成跳转链接。
导航守卫
Vue Router 提供了导航守卫(Navigation Guards),允许你在路由发生变化时执行一些逻辑,比如在进入页面之前进行身份验证,或在离开页面时进行确认操作。
全局钩子函数(beforeEach、afterEach)
- 全局前置守卫:
router.beforeEach
- 全局后置钩子:
router.afterEach
路由独享的守卫: 在路由配置中直接定义
beforeEnter
组件内钩子函数(beforeRouterEnter、beforeRouterUpdate、beforeRouterLeave)
在Vue Router的全局前置守卫(beforeEach
)中,to
、from
和next
是三个非常重要的参数,它们分别代表了即将进入的目标路由信息、当前导航正要离开的路由信息,以及一个用于解决守卫钩子的函数。下面是对这三个参数的详细解析:
1. to
- 类型:
Route
- 描述:即将要进入的目标路由对象的信息。
- 属性:
to
对象是一个路由信息对象,包含了目标路由的多个属性,如path
、query
、params
、hash
、fullPath
、matched
、name
和meta
等。你可以通过这些属性来获取目标路由的详细信息,或者基于这些信息来做出路由守卫的决策。
2. from
- 类型:
Route
- 描述:当前导航正要离开的路由对象的信息。
- 属性:与
to
对象类似,from
对象也包含了当前路由的多个属性。在路由守卫中,from
对象通常用于与to
对象进行比较,以决定是否需要执行某些操作(如重定向、警告等)。
3. next
- 类型:
Function
- 描述:
next
函数是必须调用的,用来解决守卫钩子。否则,整个路由流程都会被挂起。 - 参数:
- 无参数:直接调用
next()
会将控制权交给下一个守卫(如果有的话),或者如果没有守卫了就执行路由的进入守卫和组件内的更新守卫(beforeEnter
和beforeRouteUpdate
),然后解析异步组件,最后实例化并渲染新的组件。 - 错误:
next(error)
(2.4.0+)可以传入一个错误给router.onError()
注册的回调。 - 路径:
next('/')
或者next({ path: '/' })
:直接跳转到另一个路由,中断当前导航。 - 布尔值:
next(false)
中断当前路由的解析流程,即阻止路由跳转。 - 路由对象:
next({ ... })
或者next(to)
:与router.push
或router.replace
类似,可以跳转到另一个路由,但是当前导航被中断,且from
路由对应的组件会被销毁,to
路由对应的组件会被实例化并渲染。
- 无参数:直接调用
router.beforeEach((to, from, next) => {
// 检查目标路由是否需要认证
if (to.matched.some(record => record.meta.requiresAuth)) {
// 假设有一个获取用户认证状态的函数
if (!isAuthenticated()) {
// 用户未认证,重定向到登录页面
next({
path: '/login',
query: { redirect: to.fullPath } // 将目标路由的路径作为参数,以便登录后重定向回去
});
} else {
// 用户已认证,继续执行后续逻辑
next();
}
} else {
// 目标路由不需要认证,直接通过
next();
}
});
to.matched.some(record => record.meta.requiresAuth)
这行代码的作用是:检查即将进入的目标路由(及其所有嵌套的子路由)中,是否有任何一个路由片段需要认证(即其meta
属性中包含requiresAuth: true
)。
- 如果至少有一个路由片段需要认证,且当前用户未通过认证,则可以在全局前置守卫中进行相应的处理,如重定向到登录页面。
- 如果没有路由片段需要认证,或者用户已经通过认证,则可以继续执行后续的路由逻辑。
路由独享的钩子函数beforeEneter应用:(路由进入前想要执行的任务业务)
在Vue.js中,你可以使用路由的懒加载功能来提前预加载其他页面的业务。懒加载允许你按需加载页面组件,这意味着当用户导航到某个页面时才会加载该页面的相关代码。
const router = new VueRouter({ routes: [ { path: '/other-page', component: () => import('./OtherPage.vue'), // 在进入other-page路由之前预加载其他页面的业务逻辑 beforeEnter(to, from, next) { // 执行预加载的业务逻辑 preloadOtherPageData().then(() => { next(); }); } } ] }); // 模拟预加载其他页面的业务逻辑 function preloadOtherPageData() { return new Promise((resolve, reject) => { // 执行一些异步操作,例如加载数据 // 在这个示例中,我们简单地使用setTimeout来模拟异步操作 setTimeout(() => { console.log('Preloading other page data...'); resolve(); }, 1000); // 模拟加载时间 }); }
组件内的钩子函数
beforeRouteEnter因为触发的时候vue实例还没有创建,所以这个钩子函数中不能使用this,而beforeRouteUpdate和beforeRouteLeave都是可以访问到实例的,因为当这两个函数触发的时候实例都已经被创建了;
路由参数
props路径传参
//组件中
const user_com = {
// 使用props接收路由参数
props: ["id"],
template: '< h1>User {{ id }}组件</h1>'
};
//路由中
var router = new VueRouter({
routes: [
// 动态参数, 以冒号开头
{
path: '/user/:id',
component: user_com,
// 如果props被设置为true, route.params将会被设置为组件属性
props: true,
},
],
});
Props值为函数类型:id以函数形式传递,若以路径参数传递无效!
onst user_com = {
// 使用props接收路由参数
props: ["id", "name", "age"],
template: `
<div>
<h1>User {{ id }}组件</h1>
<h2>{{name}} ======= {{age}}</h2>
</div>`
};
var router = new VueRouter({
routes: [
{
path: '/user/:id',
component: user_com,
// 给props定义一个箭头函数
props: route => ({
name: "张三",
age: 18,
// 获取id值
id: route.params.id
})
},
],
});
params参数与query参数
params参数传递
由于动态路由也是传递params的,所以在 this.$router.push() 方法中path不能和params一起使用,否则params将无效。需要用name来指定页面【编程式,路由命名name+params】。
query参数传递
【声明式/编程式,query+path/name皆可】
1.query传递显示参数,传递不显示参数,params相对于query来说较安全一点
2.query传值页面刷新数据还在,而params传值页面刷新数据消失