文章目录
- 一、安装
- 二、基础使用
- 1、简单的示例
- 2、动态路由
- 2.1 定义动态路径参数
- 2.2 获取动态路径的参数
- 2.3 捕获所有路由
- 3、嵌套路由
- 4、编程式的导航
- 4.1 router.push
- 4.2 router.replace
- 4.3 router.go(n)
- 5、命名路由
- 6、重定向
- 三、进阶
- 1、导航守卫
- 1.1 全局前置守卫
- 1.2 全局后置钩子
- 1.3 路由独享的守卫
- 1.4 组件内的守卫
- 完整的导航解析流程
- 2、路由懒加载
一、安装
NPM
注意:vue2中需使用 v.3x 版本
npm install vue-router@3.0.0 --save
vue-router v3.x 文档:文档链接
二、基础使用
1、简单的示例
src/main.js
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
// 1. 定义 (路由) 组件。
// 可以从其他文件 import 进来
const Foo = {
template: '<div>Foo</div>'
}
const Bar = {
template: '<div>Bar</div>'
}
// 2. 定义路由
// 每个路由应该映射一个组件
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
// 3. 创建 router 实例,然后传 `routes` 配置
const router = new VueRouter({
routes
})
// 4. 通过 Vue.use() 明确地安装路由功能
Vue.use(VueRouter);
// 5. 创建和挂载根实例。
// 通过 router 配置参数注入路由,让整个应用都有路由功能
new Vue({
router,
render: h => h(App),
}).$mount('#app')
src/App.vue
<template>
<div id="app">
<p>
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/foo">Foo</router-link><br />
<router-link to="/bar">Bar</router-link>
</p>
<!-- 路由出口,路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "App",
components: {},
};
</script>
2、动态路由
2.1 定义动态路径参数
动态路径参数以冒号开头
const User = {
template: '<div>User</div>'
}
const router = new VueRouter({
routes: [
// 动态路径参数 以冒号开头
{ path: '/user/:id', component: User }
]
})
现在像 /user/123 和 /user/456 都将映射到相同的路由
2.2 获取动态路径的参数
当匹配到一个路由时,参数值会被设置到 this.$route.params
,可以在每个组件内使用
const User = {
template: '<div>User {{ $route.params.id }}</div>'
}
可以通过 $route.params
查看所有的参数信息
$route
对象还提供了其它有用的信息
const User = {
template: '<div>User {{ $route.params.id }}</div>',
created: function () {
console.log(this.$route)
}
}
当路由是 /user/101 时,$route 示例:
2.3 捕获所有路由
可以使用通配符 (*):
{
// 会匹配所有路径
path: '*'
}
{
// 会匹配以 `/user-` 开头的任意路径
path: '/user-*'
}
3、嵌套路由
要在嵌套的出口中渲染组件,需要在 VueRouter 的参数中使用 children
配置:
src/main.js
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import UserView from './components/UserView.vue'
import FooView from './components/FooView.vue'
import BarView from './components/BarView.vue'
const routes = [
{
path: '/user',
component: UserView,
children: [
{
// 当 /user/foo 匹配成功,
// FooView 会被渲染在 User 的 <router-view> 中
path: 'foo',
component: FooView
},
{
// 当 /user/bar 匹配成功,
// BarView 会被渲染在 User 的 <router-view> 中
path: 'bar',
component: BarView
},
]
},
]
const router = new VueRouter({
routes
})
Vue.use(VueRouter);
new Vue({
router,
render: h => h(App),
}).$mount('#app')
顶层 <router-view>
出口,App.vue
<template>
<div id="app">
<p>
<router-link to="/user/foo">Foo</router-link><br />
<router-link to="/user/bar">Bar</router-link><br />
</p>
<!-- 这个是顶层的 router-view -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "App",
components: {},
};
</script>
组件同样可以包含自己的嵌套 <router-view>
组件 UserView.vue
<template>
<div class="user">
<h2>User</h2>
<router-view></router-view>
</div>
</template>
组件 BarView.vue
<template>
<div>
bar
</div>
</template>
组件 FooView.vue
<template>
<div>
foo
</div>
</template>
要注意,以 / 开头的嵌套路径会被当作根路径
4、编程式的导航
4.1 router.push
这个方法会向 history 栈添加一个新的记录
代码实现路由跳转:
router.push(location, onComplete?, onAbort?)
声明式 | 编程式 |
---|---|
<router-link :to="..." > | router.push(...) |
该方法的参数可以是一个字符串路径,或者一个描述地址的对象,示例:
<template>
<div id="app">
<div>
<button @click="routeUser">字符串跳转user</button>
<button @click="routeFoo">对象跳转foo</button>
<button @click="routeBarParams">对象跳转带参数Params</button>
<button @click="routeBarQuery">对象跳转带参数Query</button>
</div>
<!-- 这个是顶层的 router-view -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "App",
components: {},
methods: {
routeUser() {
// 字符串
this.$router.push("/user");
},
routeFoo() {
// 对象
this.$router.push({path: "/foo"});
},
routeBarParams() {
// 命名的路由(带name属性)
this.$router.push({ name: 'bar', params: { id: '123' }})
},
routeBarQuery() {
// 带查询参数,变成 /bar?id=456
this.$router.push({ path: '/bar', query: { id: '456' }})
// 注意:如果提供了 path,params 会被忽略
// 下面的 params 不生效
// this.$router.push({ path: '/bar', params: { id }}) // -> /user
},
},
};
</script>
4.2 router.replace
跟 router.push 很像,唯一的不同就是,它不会向 history 添加新记录
router.replace(location, onComplete?, onAbort?)
声明式 | 编程式 |
---|---|
<router-link :to="..." replace> | router.replace(...) |
4.3 router.go(n)
这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似 window.history.go(n)。
示例:
// 在浏览器记录中前进一步,等同于 history.forward()
router.go(1)
// 后退一步记录,等同于 history.back()
router.go(-1)
// 前进 3 步记录
router.go(3)
5、命名路由
可以在创建 Router 实例的时候,在 routes 配置中使用 name
给某个路由设置名称:
const router = new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
})
6、重定向
重定向也是通过 routes 配置来完成,使用 redirect
下面例子是从 /a 重定向到 /b:
const router = new VueRouter({
routes: [
{ path: '/a', redirect: '/b' }
]
})
三、进阶
1、导航守卫
1.1 全局前置守卫
使用 router.beforeEach
注册一个全局前置守卫:
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
每个守卫方法接收三个参数:
- to: Route: 即将要进入的目标 路由对象
- from: Route: 当前导航正要离开的路由
- next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
- next(): 进行管道中的下一个钩子
- next(false): 中断当前的导航
- next(‘/’) 或者 next({ path: ‘/’ }): 跳转到一个不同的地址
确保 next 函数在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错
身份时重定向到 /login 的示例:
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) {
next({ name: 'Login' })
} else {
next()
}
})
1.2 全局后置钩子
也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:
router.afterEach((to, from) => {
// ...
})
1.3 路由独享的守卫
可以在路由配置上直接定义 beforeEnter 守卫:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
1.4 组件内的守卫
可以在路由组件内直接定义以下路由导航守卫:
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
const Foo = {
template: `...`,
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用 beforeRouteLeave 守卫。
- 调用全局的 beforeEach 守卫。
- 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
- 在路由配置里调用 beforeEnter。
- 解析异步路由组件。
- 在被激活的组件里调用 beforeRouteEnter。
- 调用全局的 beforeResolve 守卫 (2.5+)。
- 导航被确认。
- 10.调用全局的 afterEach 钩子。
- 触发 DOM 更新。
- 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入
2、路由懒加载
就是当路由被访问的时候才加载对应的组件
示例:
const Foo = () => import('./Foo.vue')
const router = new VueRouter({
routes: [{ path: '/foo', component: Foo }]
})