Vue Router 学习归纳

一、简介

在 html 中,使用 a 元素进行页面的跳转,如<a href="https://www.baidu.com">Baidu</a>
在 Vue 中,则使用 Vue Router 进行页面的跳转。
参考了Vue Router 教程Vue Router API

二、使用Vue Router

使用npm install vue-router下载 Vue Router。
在项目中新建一个 router.js 的文件,里面书写所有路由的配置。
当然,也可以将这些配置全部写在 main.js 中,建议分开使用。

import VueRouter from 'vue-router'
import Router1 from './Router1.vue'
import Router2 from './Router2.vue'

export default new VueRouter({
    routes: [
        { path: '/', component: Router1 },
        { path: '/aa', component: Router2 }
    ]
})

使用import引入 VueRouter 和要跳转的界面,再使用new VueRouter({})创建路由器实例,通过export default将实例导出。
routes选项是一个数组,数组元素是路由。路由对象也可以配置不同的key,path为路由的路径,component为路由绑定的组件。还有其他的key,将在下面介绍。

在 main.js 中将上面导出的路由器实例添加到 Vue 实例中。

import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import router from "./router.js"

Vue.config.productionTip = false
Vue.use(VueRouter)

new Vue({
    el: "#app",
    render: h => h(App),
    router: router
})

使用import引入路由器实例和 VueRouter,使用Vue.use(VueRouter)来使用插件,在new Vue({})中添加router选项,这样 Vue 就有了路由的功能。

首页是渲染在组件 APP 上的,在组件 APP 中则要渲染路由绑定的组件。

<template>
  <div id="div">
    <router-view></router-view>
    <router-link to="/aa"></router-link>
  </div>
</template>

router-view 元素是个 functional 组件,它会显示对应路由绑定的组件。
因为组件 APP 是首页,所以默认会显示path="/"的路由绑定的组件。此时<router-view></router-view>相当于<Router1></Router1>
可通过new Router({ })中的base选项来设置应用的基路径,默认为/

router-link 元素相当于一个 a 元素,点击后会跳转到path="/aa"的路由绑定的组件。

  • 命名路由
    可在路由中添加name给一个路由命名,如{ path: '/aa', component: Router2, name: "aa" }
    命名路由可使用<router-link :to="{ name: 'aa' }"></router-link>来跳转,to前要使用冒号:

三、动态路由

  1. 动态路径参数
    上面的路径是固定的,有时候我们需要根据传入的不同参数来显示不同的界面,可以使用动态路径参数。
    使用:来添加参数,如{ path: "/aa/:id",component: Router2 }aa为路径名,id为参数名。
    通过<router-link to="/aa/zhangsan123"></router-link>来设置参数值。
    在组件 Router2 中,使用this.$route.params来获取已设置的参数,此时为{ "id": "zhangsan123" }
  • 多参数
    使用{ path: "/aa/:id/:age",component: Router2 }来添加多个参数。
    通过<router-link to="/aa/zhangsan123/30"></router-link>来设置参数值,此时参数值为{ "id": "zhangsan123", "age": "30" }
  • 命名路由
    若路由是一个命名路由,如{ path: "/aa/:id/:age",component: Router2, name: "aa" }
    可通过<router-link :to="{ name: 'aa', params: { id: 'zhangsan123', age: '30' } }"></router-link>来设置参数值,此时参数值为{ "id": "zhangsan123", "age": "30" }
  1. 通配符
    使用通配符*来设置路径,如{ path: "*",component: Router2 }会匹配任意路径,通常用在404界面。
    使用通配符*来设置部分路径,如{ path: "/aa*",component: Router2 }会匹配前缀为/aa的路径,如<router-link to="/aa123"></router-link>
    使用通配符的路由,this.$route.params中会多一个keypathMatch。当路径为/aa123this.$route.params{ "pathMatch": "123" }
    注:使用通配符的应该放在routes选项的最后面,因为越往前优先级越高。

  2. 监听跳转
    有一个路由{ path: "/aa/:id",component: Router2 },当从/aa/zhangsan123跳转到/aa/lisi456时,原来的 Router2 组件会复用,这会大大减少渲染开销。
    但是,这会导致组件 Router2 的生命周期钩子函数不会被触发,此时,可使用组件export default {}中的watch选项监听$route的变化从而监听路由跳转。

watch: { 
  $route: function(to, from) { 
    var a = from.params
    var b = to.params
  }
}

to from都是路由对象,表示要进入/离开的路由。
此时两个路由是相同的,可使用from.params、to.params获取动态路径参数来判断。

也可使用组件内守卫beforeRouteUpdate来监听跳转。(守卫相当于钩子)

beforeRouteUpdate(to, from, next) {
    var a=  from.params
    var b = to.params
    next()
}

to from都是路由对象,next()表示继续触发下一个守卫,必须调用。

  1. 组件props绑定
    有一个路由{ path: "/aa/:id",component: Router2 },可以在组件 Router2 中使用this.$route.params.id获取参数值。
    在路由中添加props,如{ path="/aa/:id",component: Router2, props: true },此时路由的 id 参数绑定的值会自动绑定至组件 Router2 的自定义属性 id 上, 组件就可以使用this.id获取参数值。
    注:组件 Router2 的export default {}中也需要添加props: ["id"]
  • props的类型
    props可为布尔、对象和函数。
    • 为布尔时,如上。
    • 为对象时,可用在命名视图中,详见 五、命名视图
      { path: '/ee/:id', component: Router3, components: { default: Router5, a: Router6 }, props: { default: true, a: true } },在组件 Router5 和 Router6 中都能使用id获取参数值。
    • 为对象时,对象还可为静态值,如{ path: "/aa",component: Router2, props: { adress: "chengdu" } },在组件 Router2 中可使用adress获取参数值。
    • 为函数时,返回一个对象,对象为静态值。如{ path: "/aa",component: Router2, props: route => { return { adress: "chengdu"} } }route为路由对象。

四、嵌套路由

上面介绍的是将一个路由当做一个新的页面,但也可以将一个路由作为一个组件,这个路由就是嵌套路由。

  1. 使用嵌套路由
    在路由中添加childrenchildren是一个数组,数组元素是也是路由,如{ path: '/bb', component: Router3, children: [{ path: 'cc', component: Router4 }] }
    在组件 Router3 中需要嵌套的地方添加<router-view></router-view>
    通过<router-link to="/bb/cc"></router-link>就可以跳转到使用了嵌套路由cc的路由/bb上。
    注:children数组中的路由的path不需要使用/

  2. 嵌套路由的用法
    根据上面介绍的,实际上可以将组件 Router3 的<router-view></router-view>,直接替换成<Router4></Router4>,两者作用是相同的。

  • 嵌套路由的直正用法是根据嵌套路由的path不同,来匹配不同的界面。
    { path: '/bb', component: Router3, children: [{ path: 'cc', component: Router4 }, { path: 'dd', component: Router5 }] }
    组件 Router3 模板中只需要一句代码<router-view></router-view>
    当使用<router-link to="/bb/cc"></router-link>就会跳转到组件 Router4 的页面,使用<router-link to="/bb/dd"></router-link>就会跳转到组件 Router5 的页面。
  1. 使用动态路径参数
    你会发现,使用了嵌套路由,会匹配/bb/cc;若使用了动态路径参数,也可能会匹配/bb/cc,cc是路径为/bb的路由的参数。
    若同时使用了嵌套路由与动态路径参数,它们会如何匹配。
    若有一个路由{ path: '/bb/:id', component: Router3, children: [{ path: 'cc', component: Router4 }] }

    • 使用<router-link to="/bb/cc"></router-link>时,cc是参数id的值,此时未使用嵌套路由。
    • 使用<router-link to="/bb/zhangsan/cc"></router-link>时,zhangsan是参数id的值,cc表示嵌套路由的路径。此时组件 Router3 和 Router4 的this.$route.params的值都为{ "id": "zhangsan"}

    当路径为/bb的路由有多个动态路径参数时,如{ path: /bb/:id/:age }。此时会匹配/bb/zhangsan/20/cc,总之是按照顺序匹配的。

  • 嵌套路由中使用动态参数
    若有一个路由为{ path: '/bb/:id', component: Router3, children: [{ path: 'cc/:age', component: Router4 }] }

    • 使用<router-link to="/bb/zhangsan/cc/20"></router-link>时,zhangsan是id的值,cc是嵌套路由的路径,20是age的值。此时组件 Router3 和 Router4 的this.$route.params的值都为{ "id": "zhangsan", "age": "20"}

    总之,是按照顺序进行匹配的,且路由与嵌套路由的this.$route.params都相同。

五、命名视图

上面的嵌套路由是在页面只使用一个组件,若要在页面上使用多个组件,则需要命名视图。

  • 使用方式
    因为要在页面上添加多个组件,所以要在页面上添加多个<router-view></router-view>
    使用name属性为 router-view 元素命名,如<router-view name="a"></router-view>,未设置时默认为default
    在该页面的路由中使用components(后面有s),它是一个对象,对象的键为 router-view 元素name属性的值。如{ path: '/cc', component: Router3, components: { default: Router5, a: Router6 } }

此时,组件 Router3 中的<router-view></router-view>会被替换成 Router5,<router-view name="a"></router-view>会被替换成 Router6。
通过<router-link to="/cc"></router-link>进行跳转。

//在Router3的模板中
<template>
    <div>
        <router-view class="header"></router-view>
        <router-view name="a" class="bottom"></router-view>
    </div>
</template>

//在 router.js 中
import Router3 from './Router3.vue'
import Router5 from './Router5.vue'
import Router6 from './Router6.vue'

export default new VueRouter({
    routes: [
        { path: '/cc', component: Router3, components: {
            default: Router5
            a: Router6
        }}
    ]
})

六、导航

  1. router-link
    上面都是使用<router-link to=""></router-link>来进行导航跳转的。
    router-link 元素默认会渲染成 a 元素,绑定点击事件click。
    可使用tag属性将渲染成其他元素,如<router-link to="" tag="div"></router-link>
    可使用event属性将点击事件修改为其他事件,如<router-link to="" event="dbclick"></router-link>
  • 使用插槽
    router-link 元素也可以使用插槽与作用域插槽。
    router-link 元素默认情况下相当于下面。
<router-link to="/aa" custom v-slot="datas">
    <a :href="datas.href" @click="datas.navigate">{{ datas.route.fullPath }}</a>
</router-link>

参数datas中有几种数据:
href 解析后的 URL,会赋值给 a 元素的 href属性。
route 路由对象。
navigate 触发导航的函数,函数里面会调用this.$router.push()
isActive 为true表示链接激活时会使用类名,类名默认router-link-active
可使用 router-link 元素的active-class属性修改,也使用new Router({})中的linkActiveClass选项来全局配置。
isExactActive 为true表示精确匹配的链接激活时会使用类名,类名默认router-link-exact-active
可使用 router-link 元素的exact-active-class属性修改,也使用new Router({})中的linkExactActiveClass选项来全局配置。

注:将 router-link 元素的exact属性设为true可变成精确匹配。

  1. push
    可以给一个元素绑定一个点击事件,在点击事件中调用$router.push()来跳转页面,如<div @click="$router.push('/aa/zhangsan')">router</div>
    this.$router.push(location, onComplete, onAbort)会向 history 中添加一条新记录,点击浏览器中的后退按钮可以返回之前的页面,相当于window.history.pushState()
    有三个参数:

    • location 可为字符串或对象,是必填值。与 router-link 元素的to属性的取值相同。
      • 为字符串时,表示路由的路径,如this.$router.push("/aa/zhangsan")会匹配/aa/zhangsan。
      • 为对象时,对象中的path表示路径,query表示请求参数,如this.$router.push({ "path": "/aa", query: { "id": "zhangsan" }})会匹配/aa?id=zhangsan。
      • 为对象时,还可使用nameparamsname表示路由的名称,params是个对象,表示路由的动态路径参数。
        this.$router.push({ "name": "aa", params: { "id": "zhangsan" }})会匹配/aa/zhangsan。
        注:若使用了path,那么params会被忽略。
    • onComplete 是一个回调函数,会在导航成功完成时调用。
    • onAbort 是一个回调函数,会在导航终止时 (导航到相同的路由、或在当前导航完成之前导航到另一个不同的路由)调用。
      回调函数有一个参数 故障信息failure,可使用failure.to、failure.from获取两个路由对象,详见导航故障
  2. replace
    this.$router.replace()也能跳转页面,只不过不会向 history 中添加新记录,而是会替换当前的记录,相当于window.history.replaceState()
    参数与push()参数相同。
    replace()也与<router-link to="" replace></router-link>功能相同。

  3. 操作history
    this.$router.back()会后退一个页面,相当于window.history.back()
    this.$router.forward()会前进一个页面,相当于window.history.forward()
    this.$router.go()会前进或后退多个页面,相当于window.history.go()this.$router.go(1)相当于this.$router.forward()this.$router.go(-1)相当于this.$router.back()
    window.history.go(-100)时若历史记录不够,则不会有效果。

七、重定向与别名

  1. 重定向
    重定向的作用是当点击<router-link to="/ff"></router-link>时,实际是跳转到路径为/gg的路由。
    在路由中添加redirect,如{ path: '/ff', component: Router5, redirect: "/gg" }component可以不写,因为跳转到了/gg,Router5 并不会使用。
    注:路径为/gg的路由需要添加到routes选项中。
  • 类型
    redirect可为字符串、对象、函数。

    • 为字符串时,表示路径path的值。
    • 为对象时,对象中的name为命名路由的名称,如{ path: '/ff', redirect: { name: "gg" } }
    • 为函数时,函数返回字符串或对象,如{ path: '/ff', redirect: route => { return "/gg" } }

    注:重定向的路由需要与原路由的动态参数相同,如{ path: '/ff/:id', redirect: "/gg/:id" }

  1. 别名
    别名的作用是点击<router-link to="/ff"></router-link>后,新页面显示的 URL 不是/ff,而是/gg,但路由的路径实际还是/ff。
    在路由中添加alias,如{ path: '/ff', component: Router5, alias: "/gg" }
    通常使用别名来自由地配置显示的 URL。

八、导航守卫

导航 表示路由正在发生改变,如/bb跳转到/cc。守卫相当于钩子,会在某条件下触发,但多了个next()回调。

  1. 全局守卫或钩子
    全局守卫或钩子通常用在new VueRouter({})下面。
const router = new VueRouter({ routes: [] })
router.beforeEach((to, from, next) => {}) 
export default { router }
  • 前置守卫
    当一个导航触发时,全局前置守卫beforeEach((to, from, next) => { })会按照创建顺序调用。守卫是异步解析执行的,导航会在所有守卫 resolve 前一直等待,resolve 是指调用回调函数next()
    有三个参数:
    • to 即将要进入的路由。
    • from 即将要离开的路由。
    • next 回调函数,必须要调用回调函数来 resolve 守卫,不调用会导致守卫永远都不会被解析或报错。
      回调函数可传入参数:
      • next() 继续触发下一个守卫。如果所有守卫都触发了,则导航的状态就是 confirmed (确认的)。
      • next(false) 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动改变或者点击浏览器后退按钮),那么 URL 地址会重置到 from 路由的 URL 地址。
      • next('/aa')next({ path: '/aa' }) 跳转到另一个路由。当前的导航被中断,然后进行一个新的导航,会重新触发beforeEach守卫。
        此时next()传入的参数与this.$router.push()的第一个参数相同。
      • next(error) 传入的参数是一个 Error 实例,导航会终止且错误会传递给router.onError()中的回调函数。
  • 解析守卫
    在所有组件内守卫和异步路由组件被解析之后,全局解析守卫beforeResolve((to, from, next) => {})就会触发。
    参数与守卫beforeEach相同。
  • 后置钩子
    导航状态变为确认后,全局后置钩子afterEach((to, from) => {})就会触发。参数与守卫beforeEach相同,但少了一个next()回调。
  1. 路由内守卫
    beforeEnter守卫会在导航进入守卫beforeRouteEnter前触发,参数与守卫beforeEach相同。
    该守卫用在路由内部。
new VueRouter({ routes: [
    { path: '/aa', component: Router1, beforeEnter: (to, from, next) => {} }
] })
  1. 组件内守卫
    组件内守卫是写在组件内export default {}的。
export default {
  beforeRouteEnter(to, from, next) {
  
  }
}
  • 导航进入路由守卫
    导航开始时,导航会离开当前路由,进入到新路由,新路由的组件会触发beforeRouteEnter(to, from, next)守卫。
    通常在该守卫中调用接口获取数据,获取成功后调用next()
    参数与守卫beforeEach相同。
    注:该路由中不能访问组件实例this,因为此时实例还未创建。但是,可以在该守卫中使用next(vue => { }),vue就是组件实例,会在导航状态变为确认后触发回调。
  • 路由更新守卫
    一个使用了动态路径参数的路由{ path: "/aa/:id", component: Router },当从/aa/zhangsan跳转到/aa/lisi时,Router 组件会重用,此时就会触发beforeRouteUpdate(to, from, next)守卫。
    参数与守卫beforeEach相同。
  • 导航离开路由守卫
    导航开始时,导航会离开当前路由,进入到新路由,当前路由的组件会触发beforeRouteLeave(to, from, next)守卫。
    离开守卫通常用来禁止用户在还未保存修改前突然离开,使用next(false)来取消导航。
    参数与守卫beforeEach相同。
  1. 导航解析流程
  • 导航被触发。
  • 在当前路由的组件里调用beforeRouteLeave守卫。
  • 调用全局的beforeEach守卫。
  • 在重用的组件里调用beforeRouteUpdate守卫。
  • new VueRouter({ })里调用beforeEnter守卫。
  • 解析异步路由组件。
  • 在新路由的组件里调用beforeRouteEnter守卫。
  • 调用全局的beforeResolve守卫。
  • 导航状态变为确认。
  • 调用全局的afterEach钩子。
  • 触发 DOM 更新。
  • 调用beforeRouteEnter守卫next( vue => { })中的回调函数,组件实例会传递给回调函数。

九、滚动

当从路由切换到新的路由上时,想要页面滚动到顶部。当返回上一个页面时,想要页面滚动到原先的滚动位置。
可使用scrollBehavior选项实现该功能,该功能可以在支持history.pushState()的浏览器中使用。

export default new VueRouter({
    scrollBehavior (to, from, savedPosition) {
        if (savedPosition) {
            return savedPosition
        } else {
            return { x: 0, y: 0 }
        }
    }
})

有三个参数:

  • to 即将进入的路由。
  • form 即将离开的路由。
  • savedPosition 即将进入的路由原先的滚动位置。

需要返回一个对象:

  • x、y 向右/下滚动的距离,如return { x: 0, y: 0 }
  • selector 要滚动到的路由锚点,如return { selector: to.hash }
  • behavior 滚动模式,如return { selector: to.hash, behavior: "smooth" }表示平滑地滚动到锚点位置。

也可以返回一个 Promise,可在里面的回调中调用一些异步方法(调接口、延迟操作等)

scrollBehavior (to, from, savedPosition) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ x: 0, y: 0, behavior: "smooth" })
    }, 500)
  })
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容

  • 那这次呢?我决定直接就先放一个小小demo上来 其实我们在引入vue-router插件那一刻,我们的网页就已经附带...
    看物看雾阅读 798评论 0 1
  • Vue-router认识路由前端渲染与后端渲染url的hash和HTML5的historyvue-router的基...
    debug_LX阅读 295评论 0 0
  • 学习目的 学习Vue的必备技能,必须 熟练使用 Vue-router,能够在实际项目中运用。 Vue-rout...
    _1633_阅读 91,686评论 3 58
  • ​ 本文所用项目 GitHub 地址:https://github.com/trp1119/vue-r...
    中國式情調阅读 1,293评论 0 5
  • 路由概念 路由这一概念最早出现在后端(即后端渲染),前端是没有的。 它经历了三个阶段的演进:由后端路由(让服务器去...
    似朝朝我心阅读 1,058评论 0 6