前言:vue-router是什么?为什么我们不像原来一样直接用 a 标签编写链接?如何使用?常见路由操作有哪些?
Vue Router是什么
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:
- 嵌套的路由/视图表
- 模块化的、基于组件的路由配置
- 路由参数、查询、通配符
- 基于 Vue.js 过渡系统的视图过渡效果
- 细粒度的导航控制
- 带有自动激活的 CSS class 的链接
- HTML5 历史模式或 hash 模式,在 IE9 中自动降级
- 自定义的滚动条行为
注意:route
指的是当前页面的所有路由信息,router
是路由的方法。
router-link
<router-link to="xxx" tag=" "> // 将原本用a标签跳转的功能用router-link实现 // to是指要跳转到的目录,tag是这个点击跳转标签的样式,可以是li的样式等等
router-link-exact-active
: 路由完全匹配,当前选中
router-link-active
: 路由不完全匹配
to
: 表示目标路由的链接。当被点击后,内部会立刻把 to 的值传到 router.push(),所以这个值可以是一个字符串或者是描述目标位置的对象。
<!-- 字符串 --> <router-link to="home">Home</router-link> <!-- 渲染结果 --> <a href="home">Home</a> <!-- 使用 v-bind 的 JS 表达式 --> <router-link v-bind:to="'home'">Home</router-link> <!-- 不写 v-bind 也可以,就像绑定别的属性一样 --> <router-link :to="'home'">Home</router-link> <!-- 同上 --> <router-link :to="{ path: 'home' }">Home</router-link> <!-- 命名的路由 --> <router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link> <!-- 带查询参数,下面的结果为 /register?plan=private --> <router-link :to="{ path: 'register', query: { plan: 'private' }}">Register</router-link>
编程式导航
除了使用 router-link
标签创建 a
标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。
this.$router.push()
:括号里面参数和to的方法一致
// 字符串 router.push('home') // 对象 router.push({ path: 'home' }) // 命名的路由 router.push({ name: 'user', params: { userId: '123' }}) // 带查询参数,变成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }})
-
注意:如果提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name 或手写完整的带有参数的 path:
const userId = ‘123’
router.push({ name: ‘user’, params: { userId }}) // -> /user/123
router.push({ path:/user/${userId}
}) // -> /user/123
// 这里的 params 不生效
router.push({ path: ‘/user’, params: { userId }}) // -> /user
动态路由和嵌套路由
动态路由:一个“路径参数”使用冒号 : 标记。当匹配到一个路由时,参数值会被设置到this.$route.params
注意:子路由path不写斜线
import Home from '../views/Home' import Products from '../views/Products' import Category from '../views/Category' export default [ { path: '/home', name: 'home', component: Home }, { path: '/Products', name: 'products', component: Products, children: [{ path: ':cateName',//子路由path不写斜线 name: 'category', component: Category }] } ]
router-view
子路由(children)的router-view
要在父组件里面去配置
命名视图
有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar
(侧导航) 和 main
(主内容) 两个视图。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view
没有设置名字,那么默认为 default
<template> <div id="app"> <h2>头部</h2> <div class="main"><router-view></router-view></div> <router-view name="x-footer"></router-view> </div> </template> export default [ { path: '/home', name: 'home', components: {//这里一定要写components,default指的是没有没有命名的那个组件(在这里是app.vue) default: Home, 'x-footer': Footer } }
捕获所有路由或 404 Not found 路由
常规参数只会匹配被 / 分隔的 URL 片段中的字符。如果想匹配任意路径,我们可以使用通配符 (*):
{ // 会匹配所有路径 path: '*' } { // 会匹配以 `/user-` 开头的任意路径 path: '/user-*' }
重定向 redirect和别名alias
注意:含有通配符的路由应该放在最后
export default [ {//从"/"重定向到"/home",这样根路径就变成了home path: '/', redirect: '/home' } ]
导航守卫(常用来做权限验证)
vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航
全局前置守卫-beforeEach
全局导航守卫可以在main.js里做,因为需要在router的实例上做,用来做全局的权限验证
const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { next() })
to
: 要到哪个组件去,
from
: 从哪个组件来的
next
: 必须要调用next( )这个方法否则路由无法跳转访问
- 在路由里除了本身参数,要加入扩展参数时使用meta
组件内的守卫
const Foo = { template: `...`, beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建,在created之前就会执行这个守卫 }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` } }
beforeRouteUpdate
: 路由更新之前,这里可以发送ajax请求。在使用beforeRouteUpdate时一般会先使用beforeRouteEnter。
在beforeRouteEnter
中不能获取this,可以在next里传一个回调函数,该回调函数的第一个形参VM就是this,且beforeRouteEnter只会在第一次进来时执行一次。
在之前没有beforeRouteUpdate
,使用watch
来替代 ,watch可以watch this.上的所有东西
路由懒加载
把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,利用import返回promise来异步加载
const Foo = () => import('./Foo.vue')
把组件按组分块,下面的注释意思是:将这三个组件的代码打包到一个js文件里。
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue') const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue') const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
native
在加不上事件的时候使用,往当前组件的的根dom元素上绑定一个事件