最近小哆啦在学习之余,发现自己在vue-router中有好多不了解的知识点,小哆啦决定梳理一遍vue-router
参考资料:Vue Router (vuejs.org)
说起前端路由有些朋友可能会问什么是路由?何为前端路由?
小哆啦查阅资料之后发现其实最开始提出路由这个概念的是后端,是来跟后端服务器进行交互的一种方式,通过不同的路径,来请求不同的资源,请求不同的页面是路由的其中一种功能。
前端随着 ajax 的流行,数据请求可以在不刷新浏览器的情况下进行。异步交互体验中最盛行的就是 SPA —— 单页应用。单页应用不仅仅是在页面交互时无刷新的,连页面跳转都是无刷新的,为了实现单页应用,所以就有了前端路由。
前端路由是指在单页面应用(SPA)中,通过JavaScript来管理应用的不同视图之间的导航。
这里的路由并不是指我们平时所说的硬件路由器,这里的路由就是SPA(单页应用)的路径管理器。再通俗的说,vue-router就是WebApp的链接路径管理系统。
vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。路由模块的本质 就是建立起url和页面之间的映射关系。
至于我们为啥不能用a标签,这是因为用Vue做的都是单页应用,就相当于只有一个主的index.html页面,所以你写的标签是不起作用的,你必须使用vue-router来进行管理。
Vue Router是Vue.js官方的路由管理器。它和 Vue.js 的核⼼深度集成,让构建单⻚⾯应⽤变得易如反掌。包含的功能有:
先说一下安装吧。
安装
npm install vue-router
如果在一个模块化工程中使用它,必须要通过 Vue.use()
明确地安装路由功能:
Vue.use(VueRouter)
创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
router
}).$mount('#app')
动态路由匹配是 Vue Router 中非常强大且灵活的功能,它允许你在路由配置中定义带有动态部分的路径,并根据这些动态部分动态渲染组件或执行逻辑。
路由配置
在路由配置中使用冒号 :
来表示动态的部分,这部分会被当作参数添加到 $route.params
对象中。
const routes = [
{
path: '/user/:id',
component: User,
props: true, // 将$route.params作为组件的props传递
children: [
{
path: 'profile',
component: UserProfile,
},
{
path: 'posts',
component: UserPosts,
},
],
},
];
上述例子中,/user/:id
定义了一个动态路由,:id
是动态的部分,例如 /user/123
。路由还包含了两个子路由:/user/:id/profile
和 /user/:id/posts
。
组件中的使用
在匹配到动态路由时,路由参数会自动添加到 $route.params
对象中,可以在组件中通过 $route.params
来获取这些参数。
User Page
User ID: {{ $route.params.id }}
在这个例子中,$route.params.id
就是动态路由中的参数,例如当访问 /user/123
时,$route.params.id
就是 123
。
嵌套路由
动态路由和嵌套路由可以结合使用,形成更复杂的路由结构。在上述的路由配置中,/user/:id
下包含了两个子路由:/user/:id/profile
和 /user/:id/posts
。这种嵌套结构可以更好地组织和管理不同层次的页面。
编程式导航
在组件中,你可以使用 $router.push
进行编程式导航,传递不同的动态参数来匹配不同的路径。
// 编程式导航
this.$router.push('/user/123');
这样的导航会触发动态路由的匹配,并在组件中更新相应的参数。
5.响应路由参数的变化
当使用路由参数时,例如从 /user/foo
导航到 /user/bar
,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再 创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。
复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch (监测变化) $route
对象:
const User = {
template: '...',
watch: {
$route(to, from) {
// 对路由变化作出响应...
}
}
}
或者使用 beforeRouteUpdate
导航守卫:
const User = {
template: '...',
beforeRouteUpdate(to, from, next) {
// react to route changes...
// don't forget to call next()
}
}
有时候,同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:路由定义得越早,优先级就越高。
嵌套路由是指在 Vue Router 中,一个路由可以包含另一个路由,形成一个嵌套的关系。这种嵌套的结构使得你可以更好地组织和管理复杂的页面布局,其中某些部分的渲染是由子路由处理的。例如:
/user/foo/profile /user/foo/posts
+------------------+ +-----------------+
| User | | User |
| +--------------+ | | +-------------+ |
| | Profile | | +------------> | | Posts | |
| | | | | | | |
| +--------------+ | | +-------------+ |
+------------------+ +-----------------+
借助 vue-router
,使用嵌套路由配置,就可以很简单地表达这种关系。
路由配置:
在路由配置中,通过 children
属性定义子路由。
const routes = [
{
path: '/dashboard',
component: Dashboard,
children: [
{
path: 'profile',
component: UserProfile,
},
{
path: 'posts',
component: UserPosts,
},
],
},
];
在上述配置中,/dashboard
路由下包含了两个子路由:/dashboard/profile
和 /dashboard/posts
。
组件中的使用:
在父组件中通过
标签来指定子路由的渲染位置。
Dashboard
当访问 /dashboard
时,Dashboard
组件会渲染,并在
处渲染当前活动的子路由。
编程式导航:
在父组件中使用 $router.push
进行导航到子路由。
// 编程式导航到子路由
this.$router.push('/dashboard/profile');
嵌套子路由的组件:
在子路由对应的组件中,可以通过 $route
对象来访问路由参数。
User Profile
User ID: {{ $route.params.id }}
命名视图(Named Views):
对于复杂的布局,你可以使用命名视图来同时渲染多个视图。
Dashboard
在路由配置中,使用 components
属性定义多个组件。
const routes = [
{
path: '/dashboard',
components: {
default: Dashboard,
profile: UserProfile,
posts: UserPosts,
},
},
];
每个命名视图对应于一个具体的子路由。
通过这些方式,嵌套路由使得你可以更好地组织和管理复杂的页面结构,使得代码结构清晰,可维护性更强。
编程式导航是指通过代码来实现路由的切换,而不是通过用户的导航行为(如点击链接)触发路由的变化。Vue Router 提供了一些方法用于编程式导航,常用的方法包括 $router.push
、$router.replace
、$router.go
等。
编程式导航方法 | 声明式导航对应方式 |
---|---|
$router.push 方法: |
|
$router.replace 方法: |
<router-link :to="..." replace> |
$router.go 方法: |
通常不直接有对应的声明式导航方式,用于在导航历史中前进或后退 |
$router.push
方法$router.push
方法用于导航到一个新的 URL。它接受一个包含 path
、query
、params
等选项的对象。
this.$router.push({ path: '/user/123', query: { name: '张三' } });
在组件内部,你可以这样使用:
// 在组件中使用 $router.push
methods: {
navigateToUserPage() {
this.$router.push({ name: 'user', params: { id: 123 } });
}
}
$router.replace
方法$router.replace
方法与 $router.push
类似,但是它不会在导航历史中留下新的记录,而是替换当前的历史记录。
this.$router.replace({ path: '/user/123', query: { name: '张三' } });
$router.go
方法$router.go
方法用于在导航历史中前进或后退指定步数。
// 后退一步
this.$router.go(-1);
// 前进一步
this.$router.go(1);
在路由配置中定义了命名路由,可以通过名称进行导航。
// 在路由配置中定义命名路由
const routes = [
{ path: '/user/:id', name: 'user', component: User },
];
// 在组件中使用命名路由
this.$router.push({ name: 'user', params: { id: 123 } });
直接指定路径进行导航。
this.$router.push('/user/123');
注意事项
this.$router
访问路由实例。编程式导航通常在用户进行某些操作后触发,例如提交表单、点击按钮等。在这些情况下,你可以使用编程式导航来实现页面的切换。
命名路由是在 Vue Router 中给路由配置指定一个名称的方式。通过给路由对象添加 name
属性,你可以为路由起一个简短、有意义的名字。命名路由在编程式导航和声明式导航中都很有用。
在路由配置中使用命名路由
const routes = [
{
path: '/user/:id',
name: 'user',
component: User,
},
{
path: '/dashboard',
name: 'dashboard',
component: Dashboard,
},
];
在上述路由配置中,user
和 dashboard
就是命名路由的名称。
声明式导航中使用命名路由
在模板中使用
时,可以通过 to
属性指定命名路由:
<router-link :to="{ name: 'user', params: { id: 123 }}">User Profilerouter-link>
编程式导航中使用命名路由
在组件内部,你可以使用 $router.push
、$router.replace
、$router.go
等方法中的 name
属性进行编程式导航:
// 编程式导航到命名路由
this.$router.push({ name: 'user', params: { id: 123 } });
获取当前路由的名称
在组件内部,可以通过 $route.name
获取当前路由的名称:
// 获取当前路由的名称
const currentRouteName = this.$route.name;
为何使用命名路由
可读性和维护性: 使用命名路由可以使代码更具可读性和维护性,尤其在大型应用中,通过名称而不是路径来标识路由更容易理解。
灵活性: 使用命名路由可以在不改变路由路径的情况下修改路由配置,而不会影响到使用该路由的地方。
动态路径参数: 命名路由可以更方便地处理动态路径参数,如 :id
。
重定向是指在路由匹配时将用户重定向到另一个路径。在 Vue Router 中,可以通过 redirect
属性实现重定向。
在路由配置中使用重定向
const routes = [
{
path: '/',
redirect: '/home', // 将根路径重定向到 /home
},
{
path: '/home',
component: Home,
},
{
path: '/dashboard',
redirect: '/home', // 将 /dashboard 重定向到 /home
},
];
在上述示例中,如果用户访问根路径 /
,将被重定向到 /home
;如果用户访问 /dashboard
,同样会被重定向到 /home
。
重定向函数
你还可以使用一个函数来动态计算重定向目标。函数接收 to
路由对象作为参数,你可以基于当前的路由状态动态地决定重定向目标。
const routes = [
{
path: '/admin',
redirect: to => {
// 动态计算重定向目标
if (isAdminUser()) {
return '/admin/dashboard';
} else {
return '/login';
}
},
},
// ...
];
重定向的使用场景:
/
重定向到 /home
。别名是指为路由创建额外的路径,而不改变该路由的实际路径。这在需要提供多个路径访问同一组件的情况下很有用。在 Vue Router 中,可以通过 alias
属性实现别名。
在路由配置中使用别名:****
const routes = [
{
path: '/about',
component: About,
alias: '/about-us', // 创建别名,/about-us 也会访问 About 组件
},
{
path: '/contact',
component: Contact,
},
];
在上述示例中,当用户访问 /about
或 /about-us
时,都会渲染 About
组件。
别名函数:
别名也可以是一个函数,允许你动态计算别名路径。
const routes = [
{
path: '/admin',
component: Admin,
alias: to => {
// 动态计算别名路径
return `/dashboard${to.path}`;
},
},
// ...
];
通过使用别名和重定向,你可以更灵活地配置路由,适应不同的导航需求和场景。这些功能允许你以一种更动态和可扩展的方式管理路由。
重定向的使用场景:
/
重定向到 /home
。在 Vue Router 中,路由组件传参有多种方式,主要包括动态路径参数、查询参数、状态管理(如 Vuex)、props 和路由元信息等。下
动态路径参数是指在路由路径中使用冒号 :
定义的参数,这些参数会被 Vue Router 解析并作为 $route.params
对象传递给路由组件。
在路由配置中定义动态路径参数
const routes = [
{
path: '/user/:id',
component: User,
},
];
在路由组件中接收动态路径参数
// User.vue
export default {
mounted() {
// 获取动态路径参数
const userId = this.$route.params.id;
console.log('User ID:', userId);
},
};
查询参数是指在 URL 中使用 ?
后跟的键值对,通过 $route.query
对象传递给路由组件。
在路由组件中接收查询参数
// User.vue
export default {
mounted() {
// 获取查询参数
const queryParam = this.$route.query.param;
console.log('Query Parameter:', queryParam);
},
};
Vuex 是 Vue.js 的状态管理库,通过 Vuex 可以实现全局状态的管理,从而在不同的组件中传递数据。
在路由组件中使用 Vuex 状态
// 在路由组件中使用 Vuex 状态
export default {
computed: {
// 从 Vuex 获取状态
userName() {
return this.$store.state.user.name;
},
},
};
可以通过 props
将路由参数传递给组件。在路由配置中使用 props: true
,然后在组件中通过 props
接收参数。
在路由配置中启用 props
const routes = [
{
path: '/user/:id',
component: User,
props: true, // 启用 props
},
];
在路由组件中接收 props
// User.vue
export default {
props: ['id'],
mounted() {
// 在组件中使用 props
console.log('User ID:', this.id);
},
};
可以通过路由元信息传递额外的信息给路由组件。
在路由配置中定义元信息
const routes = [
{
path: '/user/:id',
component: User,
meta: { requiresAuth: true },
},
];
在路由组件中接收元信息
// User.vue
export default {
beforeRouteEnter(to, from, next) {
// 获取元信息
const requiresAuth = to.meta.requiresAuth;
console.log('Requires Auth:', requiresAuth);
// 使用 next 函数接收参数,可在组件实例创建前访问组件实例
next(vm => {
// 在组件实例内部使用元信息
console.log('Inside Component - Requires Auth:', vm.$route.meta.requiresAuth);
});
},
};
注意
/user/123
中的 123
。/user?id=123
中的 id=123
。props
是一个对象,它会被按原样设置为组件属性。当 props
是静态的时候有用。导航守卫(Navigation Guards)是 Vue Router 提供的一组用于在路由导航过程中进行控制的钩子函数。这些钩子函数允许你在导航到某个路由之前或之后执行一些逻辑,例如进行权限验证、取消导航、修改路由参数等。
Vue Router 提供了三种导航守卫:
beforeEach
、beforeResolve
、afterEach
。beforeEnter
。beforeRouteEnter
、beforeRouteUpdate
、beforeRouteLeave
。beforeEach(to, from, next)
next()
才能继续导航,否则路由会被中断。next()
,导航会按照调用的顺序执行。beforeResolve(to, from, next)
挺讨厌66用由于用咿咿呀呀咿咿呀呀一样一样咿呀咿呀呦也有一家他v’b’b’v’c’b’n’n’b’v’c’t’yvbbvcbnnbvcty
afterEach(to, from)
const router = new VueRouter({
routes: [...],
});
router.beforeEach((to, from, next) => {
// 在路由导航前执行逻辑,例如权限验证
if (to.meta.requiresAuth && !userLoggedIn()) {
next('/login');
} else {
next();
}
});
router.beforeResolve((to, from, next) => {
// 在导航被确认之前执行逻辑,例如解析异步路由组件
resolveAsyncComponent(to, next);
});
router.afterEach((to, from) => {
// 在每个导航完成后执行逻辑,例如埋点
trackPageView(to.path);
});
beforeEnter(to, from, next)
next()
才能继续导航,否则路由会被中断。this
。const routes = [
{
path: '/dashboard',
component: Dashboard,
beforeEnter: (to, from, next) => {
// 在进入路由前执行逻辑
if (isAdmin()) {
next();
} else {
next('/login');
}
},
},
];
beforeRouteEnter(to, from, next)
this
。next
回调函数中的参数访问组件实例。beforeRouteUpdate(to, from, next)
/user/1
切换到 /user/2
,需要重新加载用户数据。beforeRouteLeave(to, from, next)
export default {
beforeRouteEnter(to, from, next) {
// 在进入该组件前执行逻辑,不能访问组件实例
if (userNeedsConfirmation()) {
next(vm => {
// 可以访问组件实例
vm.showConfirmationDialog();
});
} else {
next();
}
},
beforeRouteUpdate(to, from, next) {
// 在路由更新但是复用该组件时触发
// 例如,可以在这里重新请求组件数据
fetchData();
next();
},
beforeRouteLeave(to, from, next) {
// 在离开当前路由时触发
// 可以执行一些清理操作
cleanup();
next();
},
};
next()
用于继续导航。next(false)
用于中断导航。next('/path')
用于重定向到指定路径。next(error)
用于中断导航并处理错误。next(vm => {})
用于在组件实例创建后执行逻辑。router.push
、router.replace
等)时,导航被触发。beforeEach
导航守卫被调用。这是在任何路由改变之前执行的全局守卫,用于执行一些全局的任务,例如权限验证。beforeEnter
导航守卫。这是在全局守卫之后、路由独享守卫之前执行的守卫。beforeResolve
导航守卫,用于解析异步组件。beforeResolve
导航守卫被调用。这是在路由解析完成之前执行的守卫。next()
表示导航被确认,可以继续。如果在上述步骤中没有中断导航的情况下,导航将被确认。afterEach
导航守卫被调用。这是在视图更新之后执行的全局守卫,用于执行一些全局的任务,例如页面埋点。路由元信息是 Vue Router 提供的一种机制,用于在路由配置中附加一些额外的信息。这些信息可以在导航守卫和组件内部使用,为路由的管理和控制提供了更多的灵活性。
在路由配置中添加路由元信息
在每个路由对象中,可以通过 meta
字段添加路由元信息。例如:
const routes = [
{
path: '/dashboard',
component: Dashboard,
meta: {
requiresAuth: true, // 用于权限验证
title: 'Dashboard Page', // 用于设置页面标题
},
},
// 其他路由配置...
];
在导航守卫中使用路由元信息
在导航守卫中,可以通过路由对象的 meta
字段访问路由元信息。例如:
router.beforeEach((to, from, next) => {
// 获取路由元信息
const requiresAuth = to.meta.requiresAuth;
// 在导航前进行权限验证
if (requiresAuth && !userLoggedIn()) {
next('/login');
} else {
next();
}
});
在组件中使用路由元信息
在组件内部,可以通过访问路由对象的 meta
字段来获取路由元信息。例如:
export default {
created() {
// 获取路由元信息
const pageTitle = this.$route.meta.title;
document.title = pageTitle || 'Default Page Title';
},
};
常见的路由元信息用途
权限验证: 使用 requiresAuth
之类的标志来表示该路由需要登录权限。
页面标题: 使用 title
字段来表示页面的标题,方便在导航守卫和组件中设置页面标题。
面包屑导航: 在路由元信息中添加用于生成面包屑导航的信息。
布局控制: 在路由元信息中添加布局相关的信息,例如是否显示侧边栏、顶部栏等。
过渡动效在Vue.js中是通过
组件实现的,它基于CSS过渡和一些JavaScript钩子函数。:
过渡动效的原理
过渡类名的生成: 过渡类名是由
组件的name
属性生成的,这个属性定义了过渡类名的前缀。例如,如果name
设置为"fade",则相关的过渡类名将是"fade-enter"、“fade-enter-active”、"fade-enter-to"等。
触发时机: 过渡动效分为进入(enter)和离开(leave)两个阶段。这些阶段是在元素插入或从DOM中移除时触发的,通常通过v-if
、v-show
或动态组件进行切换。
CSS过渡类名: Vue会自动根据状态为元素添加或移除相应的CSS类名,这些类名可以用于定义过渡效果。常见的类名有.enter-active-class
、.leave-active-class
、.enter-class
、.leave-class
等。
过渡动效的使用
包裹需要过渡的元素。
Content to be transitioned
/* 定义过渡效果的样式 */
.fade-enter-active, .fade-leave-active {
transition: opacity 1s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
组件提供的JavaScript钩子函数来处理过渡的不同阶段。
在上述代码中,toggleShow
方法用于切换show
的值,触发元素的进入或离开过渡。
这样,当你改变show
的值时,Vue会自动添加或移除相应的CSS类名,并根据定义的样式产生过渡效果。通过结合CSS和JavaScript钩子函数,你可以灵活地实现各种过渡动效。
在Vue Router中,可以通过使用滚动行为(Scroll Behavior)来定义页面切换时的滚动效果。滚动行为可以控制路由切换时页面的滚动位置,使用户在导航之间保持流畅的滚动体验。
在Vue Router中配置滚动行为需要在创建VueRouter
实例时传递scrollBehavior
选项。这个选项是一个函数,接收to
和from
两个路由对象,以及savedPosition
参数,用于控制滚动行为。
const router = new VueRouter({
routes: [
// 定义你的路由
],
scrollBehavior(to, from, savedPosition) {
// 返回期望滚动到的位置
if (savedPosition) {
return savedPosition;
} else {
return { x: 0, y: 0 };
}
},
});
Scroll Behavior 函数参数
滚动行为的函数接收三个参数:
to
:表示即将进入的路由对象。from
:表示即将离开的路由对象。savedPosition
:只有在通过浏览器的前进/后退按钮触发导航时才可用。保存了在浏览器历史记录中当前导航前的滚动位置。Scroll Behavior 函数返回值
滚动行为函数应该返回一个对象,表示期望滚动到的位置。这个对象可以包含x
和y
属性,分别表示水平和垂直方向的滚动位置。
scrollBehavior(to, from, savedPosition) {
// 通过 to.path 来判断是否进入了指定的路由
if (to.path === '/about' && from.path === '/home') {
return { x: 0, y: 0 }; // 滚动到顶部
} else {
return savedPosition || { x: 0, y: 0 }; // 使用保存的位置,或者滚动到顶部
}
}
示例
const router = new VueRouter({
routes: [
// 定义你的路由
],
scrollBehavior(to, from, savedPosition) {
if (to.hash) {
// 如果路由带有 hash 值,滚动到目标元素
return { selector: to.hash };
} else if (savedPosition) {
// 如果有 savedPosition,从保存的位置滚动
return savedPosition;
} else {
// 默认滚动到页面顶部
return { x: 0, y: 0 };
}
},
});
在这个例子中,如果路由带有哈希值(例如#section1
),则滚动到相应的元素。如果有保存的位置,使用保存的位置进行滚动。如果没有保存的位置,滚动到页面顶部。