Vue Router 是 Vue.js 的官方路由,让用 Vue.js 构建单页应用变得轻而易举
npm install vue-router@4
下面我们通过一个例子来介绍一下路由的基本使用,以下例子不是使用脚手架创建的
HTML 中的内容如下:
Hello App!
Go to Home
Go to About
JavaScript 中的内容如下:
// 1. 定义路由组件
// 也可以从其他文件导入
const Home = { template: 'Home' }
const About = { template: 'About' }
// 2. 定义一些路由
// 每个路由都需要映射到一个组件
// 我们后面再讨论嵌套路由
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About },
]
// 3. 创建路由实例并传递 `routes` 配置
// 你可以在这里输入更多的配置
const router = VueRouter.createRouter({
// 4. 内部提供了 history 模式的实现
// 为了简单起见,我们在这里使用 hash 模式
history: VueRouter.createWebHashHistory(),
routes, // `routes: routes` 的缩写
})
// 5. 创建并挂载根实例
const app = Vue.createApp({})
// 确保 _use_ 路由实例使
// 整个应用支持路由
app.use(router)
// 通过调用 app.use(router),我们可以在任意组件中以 this.$router 的形式访问它
// 也可以通过 this.$router 的形式访问当前路由
app.mount('#app')
// 现在,应用已经启动了!
下面介绍一下上面代码片段涉及到的两个内置组件 router-link 和 router-view
使得 Vue Router 可以在不重新加载页面的情况下更改 URL,处理 URL 的生成以及编码
表示目标路由的链接
当被点击后,内部会立刻把 to 的值传到 router.push()
用法如下:
Home
Home
Home
Home
User
Register
默认值:false
当 点击时,会调用 router.replace(),而不是 router.push(),所以导航后不会留下历史记录
push 执行的是压栈操作,可以保留历史记录 ?
用法如下:
custom 用来防止
将显示与 url 对应的组件,我们可以把它放在任何地方,以适应我们的布局
用法如下:
解构写法:
通过 routes 配置来完成,用法如下:
const router = new VueRouter({
routes: [
{ path: '/a', redirect: '/b' }
]
})
从 /a 重定向到 /b
所以我们也可以通过 redirect 来配置一个默认路由,用于在进入网站首页时显示
重定的向目标可以是一个命名的路由:
const router = new VueRouter({
routes: [
{ path: '/a', redirect: { name: 'foo' }}
]
})
甚至是一个方法,动态返回重定向目标:
const router = new VueRouter({
routes: [
{ path: '/a', redirect: to => {
// 方法接收 目标路由 作为参数
// return 重定向的 字符串路径/路径对象
}}
]
})
在创建路由器实例时,history 配置允许我们在不同的历史模式中进行选择
hash 模式是用 createWebHashHistory() 创建的:
它在内部传递的实际 URL 之前使用了一个哈希字符 (#)
本质上是改变 window.location 的 href 属性 ?
HTML5 模式是用 createWebHistory() 创建的:
当使用这种历史模式时,URL 会看起来很漂亮
推荐使用这个模式,但不完全是因为漂亮的原因
因为哈希模式在 SEO 中确实有不好的影响
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载
如果我们能把不同路由对应的组件分割成不同的代码块
然后当路由被访问的时候才加载对应组件,这样就会更加高效
Vue Router 支持开箱即用的 动态导入
建议对所有的路由都使用动态导入 ,不要在路由中使用异步组件
在执行打包命令的时候,有时候我们 想把某个路由下的所有组件都打包在同个异步块 (chunk) 中
只需要执行命名 chunk,一个特殊的注释语法来提供 chunk name
webpack 会将任何一个异步模块与相同的块名称组合到相同的异步块中
当然,我们也可以给每一个组件在打包时取不同的块名称
很多时候,我们需要将给定匹配模式的路由映射到同一个组件
例如,我们可能有一个 User 组件,它应该对所有用户进行渲染,但用户 ID 不同
在 Vue Router 中,我们可以在路径中使用一个动态段来实现,我们称之为路径参数
const User = {
template: 'User',
}
// 这些都会传递给 `createRouter`
const routes = [
// 动态段以冒号开始
{ path: '/users/:id', component: User },
]
现在像 /users/johnny 和 /users/jolyne 这样的 URL 都会映射到同一个路由
我们可以通过以下方法在 template 中获取当前用户的 ID
const User = {
template: 'User {{ $route.params.id }}',
}
别的地方获取好像是要加 this 的 ?
你可以在同一个路由中设置多个路径参数
使用带有参数的路由时需要注意的是,当用户从 /users/johnny 导航到 /users/jolyne 时
相同的组件实例将被重复使用
因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效
这也意味着组件的生命周期钩子不会被调用
const routes = [
// 将匹配所有内容并将其放在 `$route.params.pathMatch` 下
{ path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
// 将匹配以 `/user-` 开头的所有内容,并将其放在 `$route.params.afterUser` 下
{ path: '/user-:afterUser(.*)', component: UserGeneric },
]
?
/:pathMatch(.*) 和 /:pathMatch(.*)* 的区别在于解析的时候,是否解析 /
实际生活中的应用界面,通常由多层嵌套的组件组合而成
如下图所示:
在 User 组件中需要来回切换 Profile 组件和 Posts 组件
通过 Vue Router,我们可以使用嵌套路由配置来表达这种关系
嵌套路由的配置如下:
在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称
const router = new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
})
// 创建一个路由对象 router
const router = createRouter({
routes,
history: createWebHistory()
})
const categoryRoute = {
path: "/category",
component: () => import("../pages/Category.vue")
}
// 添加顶级路由对象
router.addRoute(categoryRoute);
// 添加二级路由对象
router.addRoute("home", {
path: "moment",
component: () => import("../pages/HomeMoment.vue")
})
vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航
这里重点讲解全局前置守卫,其它的以后再补充
我们可以使用 router.beforEach 注册一个全局前置守卫
const router = createRouter({ ... })
router.beforeEach((to, from) => {
// ...
// 返回 false 以取消导航
return false
})
每个守卫方法接收两个参数:
to:即将要进入的目标
from:当前导航正要离开的路由
可返回的值如下:
false:取消当前的导航
一个路由地址:通过一个路由地址跳转到一个不同的地址
不返回,返回 undefined 或 true:导航有效,并调用下一个导航守卫