安装

yarn add vue-router

使用

HTML:

// App.vue<script src="https://unpkg.com/vue@3"></script>
<script src="https://unpkg.com/vue-router@4"></script><div id="app"><h1>Hello App!</h1><p><!--使用 router-link 组件进行导航 --><!--通过传递 `to` 来指定链接 --><!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签--><router-link to="/">Go to Home</router-link><router-link to="/about">Go to About</router-link></p><!-- 路由出口 --><!-- 路由匹配到的组件将渲染在这里 --><router-view></router-view>
</div>

自定义路由组件:

// /components/UserPost.vue<template><div>User {{this.$route.params}} with post {{this.$route.postId}}</div>
</template>

JavaScript:

// main.js// 从vue-router引入createRouter和createWebHashHistory. 如果不引入的话,
// 使用VueRouter.createRouter()来使用
import {createRouter, createWebHashHistory} from 'vue-router'// 1. 定义路由组件.
// 也可以从其他文件导入
// (1)直接定义路由组件
const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }
// (2)从其他组件导入
import UserPost from "./components/UserPost" //(/components/下有一个名为UserPost.vue文件)// 2. 定义一些路由
// 每个路由都需要映射到一个组件。
// 我们后面再讨论嵌套路由。
const routes = [{ path: '/', component: Home },{ path: '/about', component: About },{ path: '/users/:username/posts/:postId', component: UserPost } // 此路由匹配 http://example.com/users/Jack/posts/123
]// 3. 创建路由实例并传递 `routes` 配置
// 你可以在这里输入更多的配置,但我们在这里
// 暂时保持简单
const router = createRouter({// 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。history: createWebHashHistory(),routes, // `routes: routes`的缩写
})// 5. 创建并挂载根实例
const app = Vue.createApp({})
//确保 _use_ 路由实例使
//整个应用支持路由。
app.use(router) // 此时,可以在任意组件中使用this.$router访问路由对象,并以this.$route的形式访问当前路由app.mount('#app')// 现在,应用已经启动了!

通过调用 app.use(router),我们可以在任意组件中以 this.$router 的形式访问它,并且以 this.$route 的形式访问当前路由:

路由模式

Vue Router默认采用URL hash模式来保持页面和URL的同步,其创建的URL格式需要包含井号(#),如下所示。
http://pwstrick.com/#/main

Vue Router还有另外一种history模式,利用HTML5 History来保持页面和URL的同步,其创建的URL格式在视觉上更为简洁清晰,如下所示。
http://pwstrick.com/main

在创建路由器实例时,history 配置允许我们在不同的历史模式中进行选择。

Hash 模式

hash 模式是用 createWebHashHistory() 创建的:

import { createRouter, createWebHashHistory } from 'vue-router'const router = createRouter({history: createWebHashHistory(),routes: [//...],
})

它在内部传递的实际 URL 之前使用了一个哈希字符(#)。由于这部分 URL 从未被发送到服务器,所以它不需要在服务器层面上进行任何特殊处理。不过,它在 SEO 中确实有不好的影响。如果你担心这个问题,可以使用 HTML5 模式。

HTML5 模式

用 createWebHistory() 创建 HTML5 模式,推荐使用这个模式:

import { createRouter, createWebHistory } from 'vue-router'const router = createRouter({history: createWebHistory(),routes: [//...],
})

当使用这种历史模式时,URL 会看起来很 “正常”,例如 https://example.com/user/id。

不过,问题来了。由于我们的应用是一个单页的客户端应用,如果没有适当的服务器配置,用户在浏览器中直接访问 https://example.com/user/id,就会得到一个 404 错误。这就丑了。

不用担心:要解决这个问题,你需要做的就是在你的服务器上添加一个简单的回退路由。如果 URL 不匹配任何静态资源,它应提供与你的应用程序中的 index.html 相同的页面。漂亮依旧!
具体见vue router文档-不同的历史记录模式-服务器配置实例部分。

动态路由

Vue Router采用的路径匹配引擎是path-to-regexp,它支持动态路由的匹配,例如有一个List组件,需要根据路径中的页码参数把组件渲染成不同的内容,可以像下面这样配置。

const List = { template: '<div>{{$route.params.page}}</div>' };
const routes = [{ path: '/list/:page', component: List }
];

在路由配置中,以冒号开头的:page是路径参数,它的值会被保存到路由对象$route的params属性中。路由对象不仅包含解析URL得到的信息(例如路径、查询字符串、锚点等),还有匹配到的路由信息(例如路由名称、路由记录等)。当路径是/list/1时,$route.params的值为{page: 1},params是一个对象,其键值与路径参数对应。注意,一条路径可以包含多个不同的路径参数,比如http://example.com/users/Jack/posts/123对应的路由的params为{username: Jack, postId: 123}。

匹配模式 匹配路径 $route.params
/users/:username /users/eduardo { username: ‘eduardo’ }
/users/:username/posts/:postId /users/eduardo/posts/123 { username: ‘eduardo’, postId: ‘123’ }

嵌套路由

一个被渲染的组件也可以包含自己嵌套的 <router-view>。例如,如果我们在 User 组件的模板内添加一个 <router-view>

// html<div id="app"><router-view></router-view>
</div>
// jsconst User = {template: '<div>User {{ $route.params.id }}</div>',
}// 这些都会传递给 `createRouter`
const routes = [{ path: '/user/:id', component: User }]
// User模板const User = {template: `<div class="user"><h2>User {{ $route.params.id }}</h2><router-view></router-view></div>`,
}

要将组件渲染到这个嵌套的 router-view 中,我们需要在路由中配置 children属性(和path, component同级):

const routes = [{path: '/user/:id',component: User,children: [{// 当 /user/:id/profile 匹配成功 // UserProfile 将被渲染到 User 的 <router-view> 内部path: 'profile',component: UserProfile,},{// 当 /user/:id/posts 匹配成功// UserPosts 将被渲染到 User 的 <router-view> 内部path: 'posts',component: UserPosts,},],},
]

注意,以 / 开头的嵌套路径将被视为根路径。这允许你利用组件嵌套,而不必使用嵌套的 URL。
如你所见,children 配置只是另一个路由数组,就像 routes 本身一样。因此,你可以根据自己的需要,不断地嵌套视图。
此时,按照上面的配置,当你访问 /user/eduardo 时,在 User 的 router-view 里面什么都不会呈现,因为没有匹配到嵌套路由。也许你确实想在那里渲染一些东西。在这种情况下,你可以提供一个空的嵌套路径:

// 没有匹配到路由时,可以给children提供空的嵌套路径const routes = [{path: '/user/:id',component: User,children: [// UserHome will be rendered inside User's <router-view>// when /user/:id is matched// 当 /user/:id 匹配成功// UserHome 将被渲染到 User 的 <router-view> 内部{ path: '', component: UserHome },// ...其他子路由],},
]

命名路由

可以在配置时为路由标识一个名称,从而就能在使用时省略路径了(否则需要指定的to属性为path指向的路径,如<router-link :to="/about"></router-link>)。
如下所示,name属性的值就是路由名称。

const routes = [{path: '/user/:username',name: 'user',component: User}
]

要链接到一个命名的路由,可以向 router-link 组件的 to 属性传递一个对象:

<router-link :to="{ name: 'user', params: { username: 'erina' }}">User
</router-link>

这跟代码调用 router.push() 是一回事:

router.push({ name: 'user', params: { username: 'erina' } })

在这两种情况下,路由将导航到路径 /user/erina。

命名视图

有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar (侧导航) 和 main (主内容) 两个视图,这个时候命名视图就派上用场了。如果 router-view 没有设置名字,那么默认为 default。
即页面上有多个router-view,给每个router-view指定name,让它匹配对应的路由组件。

// html<router-view class="view left-sidebar" name="LeftSidebar"></router-view> // 匹配LeftSidebar组件
<router-view class="view main-content"></router-view> // 匹配默认组件
<router-view class="view right-sidebar" name="RightSidebar"></router-view> // 匹配RightSidebar组件

一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置 (带上 s):

const router = createRouter({history: createWebHashHistory(),routes: [{path: '/',components: {default: Home,// LeftSidebar: LeftSidebar 的缩写LeftSidebar,// 它们与 `<router-view>` 上的 `name` 属性匹配RightSidebar,},},],
})

嵌套命名视图见 vue router文档-命名视图-嵌套命名视图部分。

编程式导航

除了使用 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。

导航到不同的位置

注意:在 Vue 实例中,你可以通过 router访问路由实例。因此你可以调用this.router 访问路由实例。因此你可以调用 this.router访问路由实例。因此你可以调用this.router.push。
想要导航到不同的 URL,可以使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,会回到之前的 URL。
当你点击 时,内部会调用这个方法,所以点击 相当于调用 router.push(…) :

声明式 编程式
<router-link :to="..."> router.push(…)

该方法的参数可以是一个字符串路径,或者一个描述地址的对象。例如:

// 字符串路径
router.push('/users/eduardo')// 带有路径的对象
router.push({ path: '/users/eduardo' })// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { username: 'eduardo' } })// 带查询参数,结果是 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' } })// 带 hash,结果是 /about#team
router.push({ path: '/about', hash: '#team' })

重定向和别名

重定向

重定向是指当用户访问 /home 时,URL 会被 / 替换,然后匹配成 /。
在路由配置中,通过redirect选项可重定向到一个新的页面,该选项可取的值有三种,分别是路径、命名路由和回调函数,如下所示,其中函数中的to参数表示目标路由对象。

// router.js// 配置路由对象数组routes时// redirect值为路径
const routes = [{ path: '/home', redirect: '/' }] // 当访问url为/home时,自动重定向到/// redirect值为命名路由
const routes = [{ path: '/home', redirect: { name: 'homepage' } }]// redirect值为方法(回调函数)
const routes = [{// /search/screens -> /search?q=screenspath: '/search/:searchText',redirect: to => {// 方法接收目标路由作为参数// return 重定向的字符串路径/路径对象return { path: '/search', query: { q: to.params.searchText } }},},{path: '/search',// ...},
]

别名

将 / 别名为 /home,意味着当用户访问 /home 时,浏览器地址栏URL 仍然是 /home,但会被匹配为用户正在访问 /。
例如,路由配置为:

const routes = [{ path: '/', component: Homepage, alias: '/home' }]

导航守卫

导航守卫就是路由跳转过程中的一些钩子函数,再直白点路由跳转是一个大的过程,这个大的过程分为跳转前中后等等细小的过程,在每一个过程中都有一函数,这个函数能让你操作一些其他的事儿的时机,这就是导航守卫。
Vue Router提供了三类守卫:全局、路由独享和组件级。

全局守卫

全局守卫是指路由实例上直接操作的钩子函数,他的特点是所有路由配置的组件都会触发,直白点就是触发路由就会触发这些钩子函数,如下的写法。钩子函数按执行顺序包括beforeEach、beforeResolve、afterEach三个(以下的钩子函数都是按执行顺序讲解的):

全局前置守卫 beforeEach()

在路由跳转前触发,参数包括to,from,next(参数会单独介绍)三个,其中to是目标路由对象、from是来源路由对象,next是一个回调函数,用于解析(resolve)当前守卫。这个钩子作用主要是用于登录验证,也就是路由还没跳转提前告知,以免跳转了再通知就为时已晚。

router.beforeEach((to, from, next) => {next();
});

全局解析守卫 beforeResolve()

这个钩子和beforeEach类似,也是路由跳转前触发,参数也是to,from,next三个,和beforeEach区别官方解释为:

确保在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被正确调用

即在 beforeEach 和 组件内beforeRouteEnter 之后,afterEach之前调用。

全局后置钩子 afterEach()

和beforeEach相反,他是在路由跳转完成后触发,参数包括to,from没有了next(参数会单独介绍),他发生在beforeEach和beforeResolve之后,beforeRouteEnter(组件内守卫,后讲)之前。

路由独享的守卫

路由独享的守卫是指在单个路由配置的时候也可以设置的钩子函数,其位置就是下面示例中的位置,也就是像Foo这样的组件都存在这样的钩子函数。目前他只有一个钩子函数beforeEnter:

const routes = [{path: '/users/:id',component: UserDetails,beforeEnter: (to, from) => {// reject the navigationreturn false},},
]

beforeEnter 守卫 只在进入路由时触发,不会在 params、query 或 hash 改变时触发。例如,从 /users/2 进入到 /users/3 或者从 /users/2#info 进入到 /users/2#projects。它们只有在 从一个不同的 路由导航时,才会被触发。

组件守卫

可以在路由组件内直接定义路由导航守卫(传递给路由配置的)。可以为路由组件添加以下配置:

  • beforeRouteEnter
  • beforeRouteUpdate
  • beforeRouteLeave
const UserDetails = {template: `...`,beforeRouteEnter(to, from) {// 在渲染该组件的对应路由被验证前调用// 不能获取组件实例 `this` !// 因为当守卫执行时,组件实例还没被创建!},beforeRouteUpdate(to, from) {// 在当前路由改变,但是该组件被复用时调用// 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,// 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。// 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`},beforeRouteLeave(to, from) {// 在导航离开渲染该组件的对应路由时调用// 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`},
}

(1)beforeRouteEnter():由于该组件在导航确认前被调用,因此组件还未被创建,从而访问this无法得到组件实例。但next()函数能接收一个参数为组件实例的回调,如下所示。

const List = {beforeRouteEnter: function(to, from, next) {next(vm => { //vm是组件实例});}
};

(2)beforeRouteUpdate():可通过this得到组件实例,当路由发生变化,但复用了一个组件时,会调用该守卫。例如一个路径为/list/:page的路由(如下配置所示),在将/list/1导航至list/2时,由于渲染的都是List组件,因此会调用beforeRouteUpdate()守卫。

const routes = [{path: "/list/:page",component: List}
];

(3)beforeRouteLeave():也可通过this得到组件实例,当路由改变,并且渲染的组件不同时,会调用该守卫。例如有两条路径/main和/list,分别对应Main和List组件,在List组件中声明了beforeRouteLeave()守卫(如下所示),当从/list导航至/main时,会弹出确认框,判断是否需要取消本次导航。

const List = {beforeRouteLeave: function(to, from, next) {const answer = window.confirm("是否离开当前页?");answer ? next() : next(false);}
};

导航守卫回调参数

to:目标路由对象;
from:即将要离开的路由对象;
next:他是最重要的一个参数,他相当于佛珠的线,把一个一个珠子逐个串起来。以下注意点务必牢记:

1.但凡涉及到有next参数的钩子,必须调用next() 才能继续往下执行下一个钩子,否则路由跳转等会停止。

2.如果要中断当前的导航要调用next(false)。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到from路由对应的地址。(主要用于登录验证不通过的处理)

3.当然next可以这样使用,next(’/’) 或者 next({ path: ‘/’ }): 跳转到一个不同的地址。意思是当前的导航被中断,然后进行一个新的导航。可传递的参数与router.push中选项一致。

4.在beforeRouteEnter钩子中next((vm)=>{})内接收的回调函数参数为当前组件的实例vm,这个回调函数在生命周期mounted之后调用,也就是,他是所有导航守卫和生命周期函数最后执行的那个钩子。

5.next(error): (v2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

完整的导航解析流程

  1. 导航被触发。
  2. 在失活的组件里调用 beforeRouteLeave 守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。
  5. 在路由配置里调用 beforeEnter。
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter。
  8. 调用全局的 beforeResolve 守卫(2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

参考:
Vue3 路由 | 菜鸟教程
Vue Router 官方教程
Vue躬行记(8)——Vue Router
vue-router导航守卫,不懂的来​

vue-router使用详解相关推荐

  1. 一篇由简到难的 Vue 面试题+详解答案

    作者:Big shark@LX 原文:https://juejin.cn/post/6961222829979697165 前言 本文整理了「高频」出现的 Vue 相关面试题并且附带「详解答案」 难度 ...

  2. 最全最详细前端vue面试题+详解答案(拿到高薪offer不是梦)

    最全vue面试题+详解答案 1.MVC 和 MVVM 区别 MVC MVC全名是 Model View Controller,时模型 - 视图 - 控制器的缩写,一种软件设计典范. Model(模型) ...

  3. 【面试题】973- 一篇由简到难的 Vue 面试题+详解答案

    作者:Big shark@LX 原文:https://juejin.cn/post/6961222829979697165 前言 本文整理了「高频」出现的 Vue 相关面试题并且附带「详解答案」 难度 ...

  4. 最全的 Vue 面试题+详解答案

    前言 本文整理了高频出现的 Vue 相关面试题并且附带详解答案 难度分为简单 中等 困难 三种类型 大家可以先不看答案自测一下自己的 Vue 水平哈 如果对原理感兴趣的同学 欢迎查看小编的手写 Vue ...

  5. React Router路由详解

    React Router路由详解 一.基础 1.安装使用 2.React Router 中通用的组件 路由组件 BrowserRouter 和 HashRouter 路径匹配组件: Route 和 S ...

  6. Vue组件-Confirm详解

    Vue组件-Confirm详解 原作者:爱扎马尾的小狮子 一.使用的地方引用,传入属性和方法 在需要的地方引入组件,然后传入对应的属性和方法 组件 <template> <div : ...

  7. angular4和php,Angular4的router使用详解

    这次给大家带来Angular4的router使用详解,Angular4的router使用注意事项有哪些,下面就是实战案例,一起来看一下. router,也就是路由,是前端中一个比较重要的概念.通过ro ...

  8. vue组件component详解

    vue组件component详解 组件介绍 组件: ​ 组件是拥有一定功能多个html标签的集合体,是对html标签的封装. 好处: ​ 模板中为了实现一个(例如分页)效果,需要绘制20个html标签 ...

  9. vue 源码详解(零):Vue 源码流程图

    vue 源码详解(零):Vue 源码流程图 最近在研究 Vue 的源码, 整理博客, 结果想到的.看到的内容实在是太多了, 不知道从何写起, 故整理了一个大致的流程图,根据这个顺序进行一一整理. 为了 ...

  10. Sentry For Vue 完整接入详解(2021 Sentry v21.8.x)前方高能预警!三万字,慎入!

    内容源于:https://docs.sentry.io/platforms/javascript/guides/vue/ 系列 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - 创 ...

最新文章

  1. Oracle 物理结构(六) 文件-数据文件
  2. java虚拟机 什么语言_什么是Java虚拟机?为什么Java被称为平台无关的编程语言...
  3. CSS学习01之我的第一css程序
  4. 数据写入规则IBufferWriterT
  5. 组合数学:容斥原理(HDU1976)
  6. LeetCode 242. 有效的字母异位词 (计数排序思想字符处理)
  7. oracle HWM
  8. redhat7 linux修改语言,RedHatLinux7.1中语言化完全攻略(二)
  9. python爬虫ip_python爬虫数据采集ip被封一篇解决
  10. Office2010每次打开都出现配置进度窗体
  11. Python后端实现苹果ID登陆
  12. 抖音、快手、b站都在做信息流广告,这本书教你做一个高薪的信息流优化师
  13. java添加文本框和标签_如何在column.expression中插入文本框或标签的值?
  14. xcode6.3设备无法运行Ineligible Devices的解决方法
  15. 微信小程序之首页轮播图片自适应高度
  16. HackingLab的一套渗透测试题
  17. python http服务器
  18. 基于深度学习的两种信源信道联合编码
  19. Unity SteamVR获取手柄按钮触发事件
  20. 华硕x450jn拆机_华硕X450JN笔记本拆机升级SSD,影驰ONE120固态硬盘上手

热门文章

  1. acwing——数学知识(四)Nim游戏
  2. 安卓 linux服务器文件夹,Android系统下根目录下文件
  3. 人类智商总和,网络空间智能化与互联网智商公式
  4. Brave Game
  5. vanish高速反向代理服务器配置
  6. 通信感知一体化关键技术(IMT-2030 6G)
  7. 使用flex时的自动换行
  8. 基于多机器学习模型的破产预测
  9. 3D大屏制作方法论终于来了!快码
  10. 可解释性神经网络——2.添加约束的xNN