vue - 路由(vue-router)
Vue.js
本章内容:
路由
根据不同的路径 (锚点) ,显示不同的页面 (组件) ,不会刷新整个页面,,局部更新。
官方地址: https://router.vuejs.org/zh/
引入vue-router
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
vue-router提供的组件
router-view
路由的出口,用于渲染当前路由模板,在含有导航链接的页面都与要进行路由出口,否则路由不起作用。
<router-link to="/Home">首页</router-link> <!-- 导航链接 -->
<router-view></router-view> <!-- 路由出口 -->
router-link
导航链接
<router-link to="/Home">首页</router-link>
-
标签属性
-
to (必选参数)
<router-link to="/Login">登录</router-link> <!-- 表示路由的链接, 该值可以是字符串, 可也动态绑定数据 -->
-
tag
<router-link to="/Login" tag="strong">登录</router-link> <!-- tag表示渲染成指定的标签, 同样还会监听点击, 触发路由链接。默认是<a></a>标签。 -->
-
定义路由
// 创建`router`实例,传入`routes`配置。
let router = new VueRouter({
routes: [
{
path: "/index",
component: { // 每个路由中`component`的应该映射一个组件。
template: `<h3>首页</h3>`
}
},
{
path: "/login",
component: {
template: `<h3>登录</h3>`
}
}
]
})
new Vue({
el: "#app",
router // 将`router`挂载Vue实例中。
})
动态路由
例如,我们有一个 login
组件,对于所有 ID 各不相同的用户,可以使用动态路由
将用户ID传入。
<div id="app">
<router-link to="/index">首页</router-link>
<!-- 传入用户信息 -->
<router-link to="/login/1/狗蛋/12345678">登录</router-link>
<router-view/> <!-- 路由出口 -->
</div>
// 创建`router`实例,传入`routes`信息,并定义动态路由。
let router = new VueRouter({
routes: [
{
path: "/index",
component: {
template: `<h3>首页</h3>`
}
},
{
path: "/login/:userID/:userName/:passWord", // 绑定动态路径参数,以:进行绑定某些字段。
component: {
template: `<h3>{{$route.params}}</h3>`
}
}
]
})
new Vue({
el: "#app",
router // 挂载路由
})
命名路由
命名路由指的是在每一个路由配置上,都必须提供一个name
。
const Index = {
template: "..."
}
let router = new VueRouter({
routes: [
{
name: "index", // 提供当前路由配置上的`name`。
path: "/index",
component: Index
}
]
})
$router和$route的区别
-
$router为VueRouter的实例, 是一个全局的路由对象。
-
$route是一个跳转的路由对象, 每一个路由都有
route
对象, 是一个局部对象, 包含路由路径
携带的参数,以及查询字符携带
的参数。<div id="app"> <!-- 查询参数 --> <router-link to="/index?userID=1&userName=大锤&passWord=1314521">首页</router-link> <!-- 动态参数 --> <router-link to="/login/33/狗蛋/5211314">登录</router-link> <router-view></router-view> <!-- 路由出口 --> </div>
let router = new VueRouter({ routes: [ { path: "/index", // 查询参数不需要绑定。 component: { template: ` <div> <h3>登录</h3> <h4>查询参数为:{{$route.query}}</h4> </div> ` } }, { path: "/login/:userID/:userName/:passWord", // 绑定动态路径参数,以:进行绑定某些字段。 component: { template: ` <div> <h3>登录</h3> <h4>动态参数为:{{$route.params}}</h4> </div> ` } } ] }) new Vue({ el: "#app", router // 挂载`router`实例 })
嵌套路由
路由套路由,<router-view/>
内嵌套另一个<router-view/>
组件。
<div id="app">
<router-link to="/index">首页</router-link>
<router-link to="/login">登录</router-link>
<router-view></router-view> <!-- 路由出口 -->
</div>
let router = new VueRouter({
routes: [
{
path: "/index",
component: {
template: `
<div>
<h3>首页</h3>
<router-link to="/index/child1">一入口</router-link>
<router-link to="/index/child2">二入口</router-link>
<router-link to="/index/child3">三入口</router-link>
<router-view></router-view>
</div>
`
},
children: [ // 配置index的子路由。
{
path: "child1",
component: {
template: `<h3>一入口</h3>`
}
},
{
path: "child2",
component: {
template: `<h3>二入口</h3>`
}
},
{
path: "child3",
component: {
template: `<h3>三入口</h3>`
}
}
]
},
{
path: "/login",
component: {
template: `<h3>登录</h3>`
}
}
]
})
new Vue({
el: "#app",
router: router // 将配置的路由实例挂载Vue实例中。
})
路由重定向
例如我们访问/a
路由,重定向规定为/b
,则当访问/a
就会切换到/b
路由。
let router = new VueRouter({
routes: [
{
path: "/", // `/`表示根目录,`*`会匹配任意路由路径。
redirect: "/index" // 定义重定向,如果是根目录则自动重定向到`redirect`指定的路由。
},
{
path: "/index",
component: {
template: "<h3>首页</h3>"
}
},
{
path: "/login",
component: {
template: "<h3>登录</h3>"
}
}
]
})
编程式的导航
在Vue实例内部,你可以通过$router
访问路由实例,因此你可以调用this.$router.push(...)
来导航到不同的路由。
或者使用 router.push
方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前 的 URL。
router是router实例挂载Vue实例之后自动生成的对象。而router是构造函数。
// 实例化router
let router = new VueRouter({
routes: []
})
new Vue({
el: "#app",
methods: {
routerFn() {
// $router是`router`实例挂载到Vue中才有的实例对象。
this.$route.push(...);
// router实例。
router.push(...);
console.log(router === this.$router); // true,两种效果等效,都可使用。
}
},
router // 挂载`router`实例
})
-
push
该方法参数可以是一个字符串路径,或者是一个叙述地址的对象。例如:// 字符串 this.$router.push("/index"); // 对象 this.$router.push({path: "index"}); // 命名路由,通过路由内配置的`name`值相互绑定,也可实现路由跳转。 this.$router.push({name: "index"}); // params动态路由 this.$router.push({name: "index", params: {id: 1} }); // -> {id: 1},可以通过$route.params获取。 // 查询参数,URL变成 /index?id=100 this.$router.push({name: "index", query: {id: 100} }); // -> {id: 100},可以通过$route.query获取。
如果提供了path,params就会被忽略,而
query
不会被忽略。你可以提供路由的name
或手写完整的带有参数的path
。const Id = '123'; // 提供了name,有效。 this.$router.push({name: "index", params: {Id} }); // -> /user/123 // 提供完整的`path`。 this.$router.push({ path: `/user/${Id}` }) // -> /user/123 // 这里的params不生效。 this.$router.push({path: "index", params: {Id} });
-
go
这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似window.history.go(n)
。// 在浏览器记录中前进一步,等同于 history.forward()。 this.$router.go(1); // 后退一步记录,等同于 history.back()。 this.$router.go(-1); // 前进 3 步记录 this.$router.go(3); // 如果 history 记录不够用,那就默默地失败呗 this.$router.go(-100); this.$router.go(100);
过渡动效
<router-view/>
是动态组件,所以我们可以使用<transition/>
组件给它添加一些过渡效果。
<transition name="fade">
<router-view></router-view>
</transition>
单个路由的过渡
上面语法是给所有出口都进行了相同的过渡,如果想给每个路由模板添加各自的效果,可以在<transition/>
上定义不同的name
。
const Bar = {
template: `
<transition name="fade">
<div>...</div>
</transition>
`
}
const Foo = {
template: `
<transition name="slide">
<div>...</div>
</transition>
`
}
导航守卫
vue-router
提供的导航守卫主要用来通过跳转或阻止跳转的方式守卫导航。记住参数或查询的改变并不会触发进入/离开的导航守卫
全局前置守卫
使用router.beforeEach
来注册一个全局前置守卫。
let router = new VueRouter({
routes: [
// ...
]
})
router.beforeEach((to, from, next) => {
// ...
})
同样也可以在vue中挂载的路由实例进行注册导航守卫。
let router = new VueRouter({
routes: [
// ...
]
})
new Vue({
el: "#app",
router, // ES6语法,与router: router等效
mounted() {
// 通过路由实例注册
this.$router.beforeEach((to, from, next) => {
// ...
})
}
})
-
每个守卫方法接受三个参数:
-
to
即将要进入的目标路由。 -
from
即将要离开的当前路由。 -
next
用于允许路由的切换,在路由切换中必须调用next()
, 否则钩子就不会被调用。router.beforeEach((to, from, next) => { next(); // 进行管道中的下一个钩子 next(false); // 中断当前的导航 next({path: "/login"}) // 链接到指定的路由,与`next("/login")`等效 })
-
全局后置守卫
使用router.afterEach
来注册一个全局后置守卫,但是它不接收next参数。
router.afterEach((to, from) => {
// ...
})
前置守卫与后置守卫的区别
路由独享守卫
在路由配置上直接定义beforeEnter
守卫
let router = new VueRouter({
routes: [
{
path: "/index",
component: Index,
beforeEnter(to, from, next) {
// ...
}
}
]
})
组件内部守卫
在路由组件内直接定义以下路由导航守卫 :
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`
}
}