vue路由篇

文章目录

  • 路由的理解
    • 介绍
    • 后端路由
      • 后端路由概念
      • Node.js 中的路由
    • 前端路由
      • 前端路由概念
      • 单页SPA
      • 什么时候使用前端路由
      • 前端路由有什么优点和缺点
      • 前端路由实现原理
        • hash 模式
        • hash路由的实现
        • HTML5 History 模式
  • Vue Router的介绍
    • 简介
    • 官网
    • 安装
  • Vue Router的使用步骤
    • 在浏览器中的使用
      • 第一步:安装vue-router
      • 第二步:添加路由导航链接及路由出口
      • 第三步:创建路由组件
      • 第四步:配置路由规则
      • 第五步:注入路由
    • 在脚手架中的使用
      • 第一步:安装vue-router
      • 第二步:添加路由导航链接及路由出口
      • 第三步:创建路由组件
      • 第四步:配置路由规则
      • 第五步:注入路由
  • router-link 组件
    • 作用
    • `router-link` 的Props:
      • to
      • replace
      • tag
      • active-class
      • exact
      • exact-active-class
      • event
  • router-view 组件
    • 作用
    • **`router-view` 的Props**:
    • 路由组件缓存
  • new VueRouter()
    • mode
    • base
    • linkActiveClass
    • linkExactActiveClass
    • routes
    • scrollBehavior
    • parseQuery / stringifyQuery
    • fallback
  • 根组件注入路由后的信息
    • 注入的信息
    • `$router` 与 `$route`的理解
      • `$router` 与 `$route`的关系:
      • `$router` 与 `$route`的访问:
      • `$router`和 `new VueRouter()`的关系:
      • 每个组件内的 `$route` 是不一样的
  • 路由管理器实例 router
    • router 实例属性
    • router 实例方法
      • 全局的导航守卫
      • 编程式导航
      • 添加获取路由
      • 路由事件
  • 路由对象实例 $route
    • 路由对象
    • $route出现的位置
    • $route 属性
  • 命名路由
    • 使用name命名路由
    • 使用name导航路由
    • 命名路由案例
  • 嵌套路由
    • 概念
    • 顶层路由出口
    • 嵌套的路由出口
    • 嵌套的路由
    • 带路径参数的嵌套
    • 嵌套的命名路由
  • 命名视图
    • 非嵌套的命名视图
    • 嵌套命名视图
  • 重定向和别名
    • 重定向
    • 相对重定向
    • 别名
  • 编程式导航和声明式导航
    • 声明式导航
    • 编程式导航
    • 替换当前位置
    • 横跨历史
    • 篡改历史
  • 动态路由匹配
    • 带参数的动态路由匹配
    • 响应路由参数的变化
    • 捕获所有路由或 404 Not found 路由
    • 高级匹配模式
    • 匹配优先级
  • 路由的高级匹配
    • 在参数中自定义正则
    • 可重复的参数
    • Sensitive 与 strict 路由配置
    • 可选参数
    • 调试
  • 路由传参总结
    • 第一种:动态路径传参
    • 第二种:params传参
    • 第三种:query传参
    • `$route.params`和`$route.query`的区别
    • 常见问题
      • 问题一
      • 问题二
  • 将 props 传递给路由组件
    • 布尔模式
    • 对象模式
    • 函数模式
  • 导航守卫
    • 全局导航守卫
      • 全局前置守卫
      • 全局解析守卫
      • 全局后置钩子
    • 路由独享的导航守卫
    • 组件内的导航守卫
    • 完整的导航解析流程
    • 导航守卫的例子
      • beforeEach的使用
      • beforeRouteEnter的使用
      • beforeRouteUpdate的使用
  • 历史模式
    • history 模式
    • 后端配置例子
      • 原生 Node.js
      • 基于 Node.js 的 Express
  • 路由元信息
  • 过渡动效
    • 单个路由的过渡
    • 基于路由的动态过渡
  • 滚动行为
    • scrollBehavior
    • 异步滚动
    • 平滑滚动
  • 路由组件懒加载
    • 为什么需要懒加载?
    • vue异步组件
    • ES6中的import
    • 一般组件懒加载
    • 路由懒加载的优化
  • 动态路由
    • 添加路由
    • 在导航守卫中添加路由
    • 删除路由
    • 添加嵌套路由
    • 查看现有路由

路由的理解

介绍

路由(英文:route)就是对应关系, 路由分为前端路由后端路由,比如前端路由就是 Hash 地址与组件之间的对应关系。

具体来说:一个路由就是一组key-value的对应关系

  • key 为 url 路径
  • value 可能是函数function 或 组件component

多个路由,需要经过路由器(英文:router)的管理。

vue路由篇_第1张图片

后端路由

后端路由概念

理解:value 是 函数function, 用于处理客户端提交的请求。

工作过程:服务器接收到一个请求时,根据用户请求路径URL找到对应的处理函数 来处理请求,返回响应数据。

路由这个概念最先是后端出现的。在以前用模板引擎开发页面时,经常会看到这样

http://hometown.xxx.edu.cn/bbs/forum.html

有时还会有带.asp.php的路径,这就是所谓的SSR(Server Side Render) 服务端渲染,通过服务端渲染,直接返回页面。

其响应过程是这样的

  • 浏览器发出请求

  • 服务器监听到80端口(或443)有请求过来,并解析url路径

  • 根据服务器的路由配置,返回相应信息(可以是 html 字串,也可以是 json 数据,图片等)

  • 浏览器根据数据包的Content-Type来决定如何解析数据

简单来说路由就是用来跟后端服务器进行交互的一种方式,通过不同的路径,来请求不同的资源,请求不同的页面是路由的其中一种功能。

Node.js 中的路由

在nodejs中路由是指应用程序如何响应客户端对特定端点的请求,该端点是 URL(或路径)和特定的 HTTP 请求方法(GET、POST 等)。

每个路由可以有一个或多个处理函数,当路由匹配时执行。

路由定义采用以下结构:app.method(path, handler)

  • app:express的实例
  • method:http请求方法的小写,比如:app.get()app.post()
  • path:请求的url地址
  • handler:当路由被匹配的时候执行的函数,该函数有两个参数request和response,分别表示请求对象和响应对象
app.get('/index', function (req, res) {
	res.render('index.html', {});
});

前端路由

前端路由概念

理解:value 是 组件component,用于展示页面内容。

工作过程:当浏览器的路径改变时,对应的组件就会显示。

前端路由:指的是url与组件的映射关系,据不同的 url 地址展示不同的内容或页面,通过url的变化实现页面的局部变化,而不需要刷新页面;

前端路由就是把不同路由对应不同的内容或页面的任务交给前端来做,之前是通过服务端根据 url 的不同返回不同的页面实现的。

路由与普通的js显隐实现页面切换的区别:路由有url支持分享、链接、收藏;

单页SPA

HTML5之后,流行单页网站(single page web application: SPA 单页应用),单页应用指的是一个web应用只有一个HTML页面,一个页面有不同的部分,点击页面导航部分不会刷新页面,也不会跳转页面,而是根据url地址的不同,显示不同的部分。

单页应用中不同部分的展示,需要通过组件的展示与切换来实现,所有组件的展示与切换都在这唯一的一个页面内完成。此时,不同组件之间的切换需要通过前端路由来实现。

单页应用不仅仅是在页面交互是无刷新的,连页面跳转都是无刷新的,为了实现单页应用,所以就有了前端路由。

什么时候使用前端路由

在单页面应用,大部分页面结构不变,只改变部分内容的使用

前端路由有什么优点和缺点

  • 优点

​ 用户体验好,不需要每次都从服务器全部获取,快速展现给用户

  • 缺点

​ 使用浏览器的前进,后退键的时候会重新发送请求,没有合理地利用缓存

​ 单页面无法记住之前滚动的位置,无法在前进,后退的时候记住滚动的位置

前端路由实现原理

前端路由的工作方式:

  • 用户点击了页面上的路由链接

  • 导致了 URL 地址栏中的【 Hash 值或者URL路径】发生了变化

  • 前端路由监听了到【 Hash 地址或者URL路径】的变化

  • 前端路由把当前【 Hash 地址或者URL路径】对应的组件渲染都浏览器中

hash 模式

前端路由的实现其实很简单。本质上就是检测 url 的变化,截获 url 地址,然后解析来匹配路由规则。

在 2014 年之前,大家是通过 hash 来实现路由,url hash 就是类似于

https://segmentfault.com/a/1190000011956628#articleHeader2

这种 #。后面 hash 值的变化,并不会导致浏览器向服务器发出请求,浏览器不发出请求,也就不会刷新页面。另外每次 hash 值的变化,还会触发 hashchange 这个事件,通过这个事件我们就可以知道 hash 值发生了哪些变化。

hash 的实现相对来说要简单方便些,而且不用服务器来支持。

url地址分为6部分:协议、IP(域名)、端口号、路径、参数、hash哈希值。

http://www.example.com/login?username=tom#print

哈希值:url中第一个#后边的内容都是这个url的哈希值

url中的哈希值是给前端浏览器使用的,最初,浏览器能够使用hash实现页面锚点。

hash仅作为前端浏览器的参考,当浏览器根据一个url向服务器发送请求时,哈希值是不会发送的。

hashchange 使用来监听页面hash值的变化的事件:window.addEventListener(“hashchange”, fun);

假如我们要用 hash 的模式实现一个路由,那么流程应该是这样的。

vue路由篇_第2张图片

hash路由的实现

<nav>
  <div class="w">
    <a href="#home">首页a>
    <a href="#friend">好友a>
    <a href="#setting">设置a>
  div>
nav>

<div class="w">
  <div id="view">div>
div>

<script>
  const page = {
    home: `

这是首页

`
, friend: `

好友页面

`
, setting: `

关于页面

`
, } const view = document.getElementById("view"); // 设置首页 view.innerHTML = page.home; // 当页面url中的哈希值发生变化时触发 window.onhashchange = function (ev) { const index = ev.newURL.indexOf("#"); const hash = ev.newURL.substring(index + 1); view.innerHTML = page[hash]; }
script>
HTML5 History 模式

14年后,因为HTML5标准发布。多了两个 API,pushStatereplaceState,通过这两个 API 可以改变 url 地址且不会发送请求。同时还有 onpopstate 事件。通过这些就能用另一种方式来实现前端路由了,但原理都是跟 hash 实现相同的。用了 HTML5 的实现,单页路由的 url 就不会多出一个#,变得更加美观。但因为没有 # 号,所以当用户刷新页面之类的操作时,浏览器还是会给服务器发送请求。为了避免出现这种情况,所以这个实现需要服务器的支持,需要把所有路由都重定向到根页面。

假如我们要用 History 的模式实现一个路由,那么流程应该是这样的。

vue路由篇_第3张图片

Vue Router的介绍

简介

前端路由是现代SPA应用必备的功能,每个现代前端框架都有对应的实现,例如vue-router、react-router。

Vue Router是Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,使用 Vue.js + Vue Router 让构建单页面应用变得易如反掌。包含的功能有:

  • 嵌套的路由/视图表
  • 模块化的、基于组件的路由配置
  • 路由参数、查询、通配符
  • 基于 Vue.js 过渡系统的视图过渡效果
  • 细粒度的导航控制
  • 带有自动激活的 CSS class 的链接
  • HTML5 历史模式或 hash 模式,在 IE9 中自动降级
  • 自定义的滚动条行为

官网

vue-router目前主要有两个版本v3.x和v.4x。

  • Vue2.x对应vue-router的v3.x版本

  • Vue3.x对应vue-router的v4.x版本

v3版本的官网:https://v3.router.vuejs.org/zh/

v4版本的官网:https://router.vuejs.org/zh/

安装

以Vue2中的方式使用为例:

方式一:在浏览器中直接使用,需要使用script标签导入vue-router.js

<script src="https://unpkg.com/vue-router@3/dist/vue-router.js">script>

方式二:在脚手架中使用

安装vue-router的时候需要指定版本

  • vue2.x对应vue-router3.x:npm install vue-router@3
  • vue3.x对应vue-router4.x:npm install vue-router@4

Vue Router的使用步骤

在浏览器中的使用

第一步:安装vue-router

<script src="https://unpkg.com/vue-router@3/dist/vue-router.js">script>

第二步:添加路由导航链接及路由出口

在Vue根组件的模板中添加添加路由导航链接及路由出口

  • 路由导航链接:点击不同的导航链接,导航到匹配的组件
  • 路由出口:导航链接匹配的组件渲染的位置
<div id="app">
  <nav id="nav-list">
    <div class="w">
      
      
      
      <router-link to="/">首页router-link>
      <router-link to="/friend">好友router-link>
      <router-link to="/setting">设置router-link>
    div>
  nav>

  <div class="w">
    
  	
    <router-view id="view">router-view>
  div>
div>

第三步:创建路由组件

这一步就是创建vue组件,等配置好路由之后,随后将组件映射到路由。

  • 路由组件不需要使用Vue.component() 或者 components 注册,直接使用组件配置对象创建。
  • 当路由路径匹配的时候,会在路由出口自动渲染路由组件
  • 路由组件默认没有名字,可以通过name选项给组件起名字,方便调试
const home = {
  name: 'Home',
  template: '

首页

'
, } const friend = { name: 'Friend', template: '

好友

'
, } const setting = { name: 'Setting', template: '

设置

'
, }

第四步:配置路由规则

这一步主要是创建路由管理器对象 router,并配置路由列表(路由表)routes

先创建路由对象route,把每一个路由对象存入数组 routes 中,在路由对象中配置路由规则:

  • path:定义路由url地址,一个url路径对应一个组件
  • component:定义路由url地址映射的Vue组件
const routes = [
  { path: '/', component: home },
  { path: '/friend', component: friend },
  { path: '/setting', component: setting },
];

再创建路由管理器对象router,创建路由管理器对象的时候,需要传入上面定义的路由规则对象routes:

const router = new VueRouter({
  routes, // (缩写) 相当于 routes: routes
});

也可以把上面两步合并在一起:

const router = new VueRouter({
  routes: [
    { path: '/', component: home },
    { path: '/friend', component: friend },
    { path: '/setting', component: setting },
  ]
});

第五步:注入路由

在根组件实例中通过 router 配置参数注入路由,从而让整个应用都有路由功能:

new Vue({
  el: '#app',
  router, // (缩写) 相当于 router: router,
});

在脚手架中的使用

vue脚手架项目目录分析:

  • public是静态资源文件夹。

  • src是项目源代码文件夹,整个项目的所有代码都再src中。在src文件夹中,main.js是整个项目的入口文件。当运行项目时,vue-cli会使用webpack对main.js进行打包。

    • main.js 入口文件

    • App.vue 根组件下的app组件,后面所有的组件是添加在app组件内

    • components 目录 存放一般组件

    • views/pages 目录 存放路由组件

    • router目录 存放路由的配置文件index.js

    • store目录 存放vuex的配置文件

    • assets目录 存放静态资源

一般组件和路由组件都是vue的单文件组件,创建方式是一样的。

  • 一般组件:可以导入到任意组件中使用,导入之后一定要在当前组件内的components属性中注册组件
  • 路由组件:路由组件用在路由配置文件文件中,不需要注册,通过路由匹配,直接渲染在路由出口的组件

第一步:安装vue-router

npm install vue-router@3

第二步:添加路由导航链接及路由出口

App.vue组件中添加路由导航链接及路由出口

// app.vue


第三步:创建路由组件

路由组件都放在src目录下的views或者pages文件中

第四步:配置路由规则

在项目src目录中创建router文件夹,在文件中创建index.js文件,在index.js文件中配置路由

  • 在一个模块化的打包系统中,您必须显式地通过 Vue.use() 来安装 vue-router:
// router/index.js

import Vue from 'vue';
import VueRouter from 'vue-router';

Vue.use(VueRouter);

// 导入路由组件
import home from '../views/home.vue';
import friend from '../views/friend.vue';
import setting from '../views/setting.vue';

const router = new VueRouter({
  routes: [
    { path: '/', component: home},
    { path: '/friend', component: friend},
    { path: '/setting', component: setting},
  ],
});

// 导出路由
export default router;

第五步:注入路由

在main.js导入路由配置文件 index.js,并在根组件中注入路由

// main.js

import Vue from 'vue';
import App from './App.vue';

// 导入路由配置文件
import router from './router';


Vue.config.productionTip = false;
new Vue({
  render: h => h(App),
  router,// 注入路由
}).$mount('#app');

router-link 组件

作用

组件用于设置导航链接。 通过 to 属性指定目标地址,默认渲染成带有正确链接的 标签,可以通过配置 tag 属性生成别的标签.。另外,当目标路由成功激活时,链接元素自动设置一个表示激活的 CSS 类名。

比起写死的 会好一些,理由如下:

  • 无论是 HTML5 history 模式还是 hash 模式,它的表现行为一致,所以,当你要切换路由模式,或者在 IE9 降级使用 hash 模式,无须作任何变动。
  • 在 HTML5 history 模式下,router-link 会守卫点击事件,让浏览器不再重新加载页面。
  • 当你在 HTML5 history 模式下使用 base 选项之后,所有的 to 属性都不需要写 (基路径) 了。

请注意,我们没有使用常规的 a 标签,而是使用一个自定义组件 router-link 来创建链接。这使得 Vue Router 可以在不重新加载页面的情况下更改 URL,处理 URL 的生成以及编码。我们将在后面看到如何从这些功能中获益。

router-link 的Props:

to

  • to是必须设置的属性。
  • 表示目标路由的链接。当被点击后,内部会立刻把 to 的值传到 router.push(),所以这个值可以是一个字符串或者是描述目标位置的对象

<router-link to="/home">Homerouter-link>

<a href="/home">Homea>


<router-link :to="'/home'">Homerouter-link>


<router-link :to="{ path: '/home' }">Homerouter-link>


<router-link :to="{ name: 'user', params: { userId: '123' }}">Userrouter-link>


<router-link :to="{ path: '/register', query: { plan: 'private' }}">
  Register
router-link>

replace

  • 默认值为 false。
  • 设置 replace 属性的话,当点击时,会调用 router.replace() 而不是 router.push(),于是导航后不会留下 history 记录。
<router-link to="/abc" replace>router-link>

tag

  • 默认值: "a"
  • tag 指定渲染为何种标签,默认为a标签。设置为其他标签它还是会监听点击,触发导航。
<router-link to="/foo">foorouter-link>

<a to="/foo">foo<a>

<router-link to="/foo" tag="li">foorouter-link>

<li>fooli>

active-class

  • 默认值: "router-link-active"

  • 设置链接激活时使用的 CSS 类名。默认值可以通过路由的构造选项 linkActiveClass 来全局配置。

exact

  • 默认值: false

  • “是否激活”默认类名的依据是包含匹配。 举个例子,如果当前的路径是 /a 开头的,那么 也会被设置 CSS 类名。

按照这个规则,每个路由都会激活 !想要链接使用“精确匹配模式”,则使用 exact 属性:


<router-link to="/" exact>router-link>

exact-active-class

  • 默认值: "router-link-exact-active"

  • 配置当链接被精确匹配的时候应该激活的 class。注意默认值也是可以通过路由构造函数选项 linkExactActiveClass 进行全局配置的。

event

  • 默认值: 'click'

  • 声明可以用来触发导航的事件。可以是一个字符串或是一个包含字符串的数组。

  • 绑定原生DOM事件依然需要添加 .native 修饰符

router-view 组件

作用

router-view 将显示与 url 对应的组件。你可以把它放在任何地方,以适应你的布局。

组件是一个 functional 组件,渲染路径匹配到的视图组件。 渲染的组件还可以内嵌自己的 ,根据嵌套路径,渲染嵌套组件。

  • 其他属性 (非 router-view 使用的属性) 都直接传给渲染的组件,比如 calss属性, 很多时候,每个路由的数据都是包含在路由参数中。

  • 因为它也是个组件,所以可以配合 使用。如果两个结合一起用,要确保在内层使用

<transition>
  <keep-alive>
    <router-view>router-view>
  keep-alive>
transition>

router-view 的Props

name

  • 默认值: "default"
  • 如果 设置了名称,则会渲染对应的路由配置中 components 下的相应组件,常用于命名组件。

路由组件缓存

当路由匹配到新的组件之后,原来的组件被销毁,新的组件被创建。

路由缓存:使用keep-alive包裹router-view把切换出去的组件缓存起来。

new VueRouter()

new VueRouter() 用于创建一个可以被 Vue 应用程序使用的路由管理器实例,参数是一个配置对象,有以下可以传递的属性列表:

new VueRouter({
  mode:'',
  base:'',
  linkActiveClass:'',
  linkExactActiveClass:'',
  routes:[],
  scrollBehavior(){},
  parseQuery / stringifyQuery: Function,
  fallback: true,
});

mode

  • 默认值: "hash" (浏览器环境) | "abstract" (Node.js 环境)
  • 可选值: "hash" | "history" | "abstract"
  • 配置路由模式:
    • hash: 使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器。
    • history: 依赖 HTML5 History API 和服务器配置。
    • abstract: 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式。

base

  • 默认值: "/"
  • 应用的基路径。例如,如果整个单页应用服务在 /app/ 下,然后 base 就应该设为 "/app/"

linkActiveClass

  • 默认值: "router-link-active"

  • 全局配置 默认的激活的 class。如果什么都没提供,则会使用 router-link-active。

linkExactActiveClass

  • 默认值: "router-link-exact-active"
  • 全局配置 默认的精确激活的 class。如果什么都没提供,则会使用 router-link-exact-active

routes

当用户通过 routes 选项或者 router.addRoute() 来添加路由时,可以得到路由记录。 有三种不同的路由记录:

  • 单一视图记录:有一个 component 配置
  • 多视图记录:有一个 components 配置
  • 重定向记录:没有 componentcomponents 配置,因为重定向记录永远不会到达。

routes 选项用来配置应该添加到路由的初始路由列表,路由表数组中存放的是一个一个的路由对象。

我们称呼 routes 配置中的每个路由对象为 路由记录。路由记录可以是嵌套的,在 children 数组存放的路由对象也是路由记录。

const router = new VueRouter({
  routes: [
    // 下面的对象就是路由记录
    {
      path: '/foo',
      component: Foo,
      children: [
        // 这也是个路由记录
        { path: 'bar', component: Bar }
      ]
    }
  ]
})

路由记录的值是一个对象类型 RouteConfig ,路由记录有以下可以传递的属性列表:

interface RouteConfig = {
  path: string,// 导航路径
  component?: Component,// 路由导航链接匹配的组件
  name?: string, // 命名路由
  components?: { [name: string]: Component }, // 命名视图组件
  redirect?: string | Location | Function, // 重定向
  props?: boolean | Object | Function, // props参数
  alias?: string | Array<string>, // 别名
  children?: Array<RouteConfig>, // 嵌套路由
  beforeEnter?: (to: Route, from: Route, next: Function) => void,
  meta?: any, // 元信息
  caseSensitive?: boolean, // 匹配规则是否大小写敏感?(默认值:false)
  pathToRegexpOptions?: Object // 编译正则的选项
}
  • path:路由导航链接的路径,和router-link组件的to属性保持一致。应该以 / 开头,除非该记录是另一条记录的子记录。可以定义参数:/users/:id 匹配 /users/1 以及 /users/posva

  • component:路由导航链接匹配的组件。

  • name:路由记录独一无二的名称。

  • components:命名视图的字典,如果没有,包含一个键为 default 的对象。

  • redirect:如果路由是直接匹配的,那么重定向到哪里呢。重定向发生在所有导航守卫之前,并以新的目标位置触发一个新的导航。也可以是一个接收目标路由地址并返回我们应该重定向到的位置的函数。

  • props:允许将参数作为 props 传递给由 router-view 渲染的组件。当传递给一个多视图记录时,它应该是一个与组件具有相同键的对象,或者是一个应用于每个组件的布尔值

  • alias:路由的别名。允许定义类似记录副本的额外路由。这使得路由可以简写为像这种 /users/:id/u/:id所有的 aliaspath 值必须共享相同的参数

  • children:当前记录的嵌套路由。

  • beforeEnter:允许将参数作为 props 传递给由 router-view 渲染的组件。当传递给一个多视图记录时,它应该是一个与组件具有相同键的对象,或者是一个应用于每个组件的布尔值

  • meta:路由元信息,在记录上附加自定义数据。

  • caseSensitive:使路由匹配区分大小写,默认为false。注意这也可以在路由级别上设置。

  • pathToRegexpOptions:编译正则的选项

scrollBehavior

  • scrollBehavior 在页面之间导航时控制滚动的函数。

parseQuery / stringifyQuery

  • 提供自定义查询字符串的解析/反解析函数。覆盖默认行为。

fallback

  • 默认值: true
  • 当浏览器不支持 history.pushState 控制路由是否应该回退到 hash 模式。默认值为 true
  • 在 IE9 中,设置为 false 会使得每个 router-link 导航都触发整页刷新。它可用于工作在 IE9 下的服务端渲染应用,因为一个 hash 模式的 URL 并不支持服务端渲染。

根组件注入路由后的信息

注入的信息

通过在 Vue 根实例的 router 配置传入 router 实例,会给Vue实例的根组件及其所有的子级组件注入以下信息:

  • 注入的属性,下面这些属性成员会被注入到每个子组件:

    • this.$router:router 实例。和 new VueRouter() 创建的路由管理器对象功能一致。

    • this.$route:当前激活的路由对象(路由信息对象)。这个属性是只读的,里面的属性是 immutable (不可变) 的,不过你可以 watch (监测变化) 它。

  • 增加的组件配置选项,这些都是组件内的守卫:

    • beforeRouteEnter

    • beforeRouteUpdate

    • beforeRouteLeave

$router$route的理解

$router$route的关系:

一个Vue应用只有一个路由管理器对象router,当匹配一条路由记录就会生成一个新的路由对象route,多个路由对象route是通过路由管理器对象router来管理的。

  • $router 是路由管理器对象,在组件内使用 $router 获取,可以获取当前路由对象,也可以调用一些函数控制路由前进、后退、绑定路由导航守卫等。
  • $route 是路由对象,在组件内使用 $route 获取,表示当前激活的路由的状态信息,存储了当前路由的路径信息、路径参数等内容。

$router$route的访问:

在 Vue 根实例的 router 配置项传入 router 实例后:

  • 在任意组件实例中可以通过 this.$router来访问路由管理对象 router,或者在组件的模板中使用 $router
  • 在任意组件实例中可以通过 this.$route来访问路由对象 ,或者在组件的模板中使用 $route

$routernew VueRouter()的关系:

一个Vue应用只有一个路由管理器对象router,在整个文档中,我们会经常使用 router 实例,请记住:

  • 在组件中获取的this.$router 与直接使用通过 new VueRouter()创建的 router 实例完全相同。
  • 我们使用 this.$router 的原因是,我们不想在每个需要操作路由的组件中都导入路由。

每个组件内的 $route 是不一样的

每一个路由组件都有自己的路由对象,使用 $route 获取:在组件内通过 this.$route 使用;在组件的模板中可以直接使用 $route

$route:路由对象是不可变 (immutable) 的,每次成功的导航后都会产生一个新的路由对象。所以在每一个匹配成功的路由组件中都有一个$route

路由管理器实例 router

router 实例属性

  • router.app:配置了 router 的 Vue 根实例。

  • router.mode:路由使用的模式。

  • router.currentRoute:当前路由管理器对应的路由对象

  • router.START_LOCATION:以路由对象的格式展示初始路由地址,即路由开始的地方。可用在导航守卫中以区分初始导航。

import VueRouter from 'vue-router'

const router = new VueRouter({
  // ...
})

router.beforeEach((to, from) => {
  if (from === VueRouter.START_LOCATION) {
    // 初始导航
  }
})

router 实例方法

全局的导航守卫

  • router.beforeEach

  • router.beforeResolve

  • router.afterEach

router.beforeEach((to, from, next) => {
  /* 必须调用 `next` */
})

router.beforeResolve((to, from, next) => {
  /* 必须调用 `next` */
})

router.afterEach((to, from) => {})

编程式导航

  • router.push

  • router.replace

  • router.go

  • router.back

  • router.forward

router.push(location, onComplete?, onAbort?)
router.push(location).then(onComplete).catch(onAbort)
router.replace(location, onComplete?, onAbort?)
router.replace(location).then(onComplete).catch(onAbort)
router.go(n)
router.back()
router.forward()

添加获取路由

  • router.resolve:解析目标位置 (格式和 to prop 一样)。

    • current 是当前默认的路由 (通常你不需要改变它)

    • append 允许你在 current 路由上附加路径 (如同 router-link)

const resolved: {
  location: Location;
  route: Route;
  href: string;
} = router.resolve(location, current?, append?)
  • router.addRoutes:动态添加更多的路由规则。参数必须是一个符合 routes 选项要求的数组。

已废弃:使用 router.addRoute()代替。

router.addRoutes(routes: Array<RouteConfig>)
  • router.addRoute:添加一条新路由规则。如果该路由规则有 name,并且已经存在一个与之相同的名字,则会覆盖它。
addRoute(route: RouteConfig): () => void
  • router.addRoute:添加一条新的路由规则记录作为现有路由的子路由。如果该路由规则有 name,并且已经存在一个与之相同的名字,则会覆盖它。
addRoute(parentName: string, route: RouteConfig): () => void
  • router.getRoutes:获取所有活跃的路由记录列表。注意只有文档中记录下来的 property 才被视为公共 API,避免使用任何其它 property,例如 regex,因为它在 Vue Router 4 中不存在。

路由事件

  • router.onReady
router.onReady(callback, [errorCallback])

该方法把一个回调排队,在路由完成初始导航时调用,这意味着它可以解析所有的异步进入钩子和路由初始化相关联的异步组件。

这可以有效确保服务端渲染时服务端和客户端输出的一致。

第二个参数 errorCallback 只在 2.4+ 支持。它会在初始化路由解析运行出错 (比如解析一个异步组件失败) 时被调用。

  • router.onError
router.onError(callback)

注册一个回调,该回调会在路由导航过程中出错时被调用。注意被调用的错误必须是下列情形中的一种:

  • 错误在一个路由守卫函数中被同步抛出;
  • 错误在一个路由守卫函数中通过调用 next(err) 的方式异步捕获并处理;
  • 渲染一个路由的过程中,需要尝试解析一个异步组件时发生错误。

路由对象实例 $route

路由对象

我们称呼 routes 配置中的每个路由对象为 路由记录。一个路由匹配到的所有路由记录会暴露为 $route 对象,称作 路由对象

  • 一个路由对象 (route object) 表示当前激活的路由的状态信息,包含了当前 URL 解析得到的信息,还有 URL 匹配到的路由记录 (route records)

  • 路由对象是不可变 (immutable) 的,每次成功的导航后都会产生一个新的对象。

$route出现的位置

路由对象出现在多个地方:

  • 在组件内,即 this.$route

  • $route 观察者回调内

  • router.match(location) 的返回值

  • 导航守卫的参数:

    router.beforeEach((to, from, next) => {
      // `to` 和 `from` 都是路由对象
    })
    
  • scrollBehavior 方法的参数:

    const router = new VueRouter({
      scrollBehavior(to, from, savedPosition) {
        // `to` 和 `from` 都是路由对象
      }
    })
    

$route 属性

  • $route.path:当前路由的路径,总是解析为绝对路径,如 "/foo/bar"

  • $route.params:一个 key/value 对象,包含了动态片段和全匹配片段,如果没有路由参数,就是一个空对象。

  • $route.query:一个 key/value 对象,表示 URL 查询参数。例如,对于路径 /foo?user=1,则有 $route.query.user == 1,如果没有查询参数,则是个空对象。

  • $route.hash:当前路由的 hash 值 (带 #) ,如果没有 hash 值,则为空字符串。

  • $route.fullPath:完成解析后的 URL,包含查询参数和 hash 的完整路径。

  • $route.meta:附加到从父级到子级合并(非递归)的所有匹配记录的任意数据。

  • $route.matched:一个数组,包含当前路由的所有嵌套路径片段的路由记录 。路由记录就是 routes 配置数组中的对象副本 (还有在 children 数组)。

    const router = new VueRouter({
      routes: [
        // 下面的对象就是路由记录
        {
          path: '/foo',
          component: Foo,
          children: [
            // 这也是个路由记录
            { path: 'bar', component: Bar }
          ]
        }
      ]
    })
    

    当 URL 为 /foo/bar$route.matched 将会是一个包含从上到下的所有对象 (副本)。

  • $route.name:当前路由的名称,如果有的话。

  • $route.redirectedFrom:如果存在重定向,即为重定向来源的路由的名字。

命名路由

使用name命名路由

除了 path 之外,你还可以为任何路由提供 name。这有以下优点:

  • 没有硬编码的 URL
  • params 的自动编码/解码。
  • 防止你在 url 中出现打字错误。
  • 绕过路径排序(如显示一个)
const routes = [
  {
    path: '/user/:username',
    name: 'user',
    component: User,
  },
]

使用name导航路由

要链接到一个命名的路由,可以向 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

命名路由案例

<div id="app">
  <nav id="nav-list">
    <div class="w">
      <router-link :to="{name:'home'}">首页router-link>
      <router-link :to="{name:'friend'}">好友router-link>
      <router-link :to="{name:'setting'}">设置router-link>
    div>
  nav>
  <div class="w">
    <router-view id="view">router-view>
  div>
div>

<script>
  const home = { template: '
首页
'
} const friend = { template: '
好友
'
} const setting = {template: '
设置
'
,} const router = new VueRouter({ routes: [ { path: '/', component: home, name: 'home' }, { path: '/friend', component: friend, name: 'friend' }, { path: '/setting', component: setting, name: 'setting' }, ] }); new Vue({ el: '#app', router, });
script>

嵌套路由

概念

一些应用程序的 UI 由多层嵌套的组件组成。在这种情况下,URL 的片段通常对应于特定的嵌套组件结构,例如:

/setting/login                     /user/regist
+------------------+                  +-----------------+
| setting          |                  | Setting         |
| +--------------+ |                  | +-------------+ |
| | login        | |  +------------>  | | regist      | |
| |              | |                  | |             | |
| +--------------+ |                  | +-------------+ |
+------------------+                  +-----------------+

通过 Vue Router,你可以使用嵌套路由配置来表达这种关系。

顶层路由出口

顶层的路由出口(主路由出口):

  • 在根组件模板中添加 是主路由出口
  • 主路由出口只有一个
  • 主路由出口渲染顶层路由匹配的组件
<div id="app">
  <nav id="nav-list">
    <div class="w">
      <router-link to="/">首页router-link>
      <router-link to="/friend">好友router-link>
      <router-link to="/setting">设置router-link>
      <router-link to="/setting/login">登录router-link>
      <router-link to="/setting/regist">注册router-link>
    div>
  nav>

  
  <div class="w">
    <router-view id="view">router-view>
  div>
div>

嵌套的路由出口

同样地,一个被渲染的组件也可以包含自己嵌套的 。例如,如果我们在 Setting 组件的模板内添加一个

  • 在setting组件中的是嵌套的路由出口(子路由的出口)
  • 子路由出口可能有很多个
  • 子路由出口渲染的是嵌套路由匹配的组件
const Home = { template: '

首页

'
}; const Friend = { template: '

好友

'
}; const Setting = { template: '

设置

'
}; const Login = {template: '
登录
'
}; const Regist = {template: '
注册
'
};

嵌套的路由

要将组件渲染到这个嵌套的 router-view 中,我们需要在路由中配置 children

  • children 用来添加子路由,每一个路由都可以添加子路由,一个子路由对应一个子路由的出口
  • 如你所见,children 配置只是另一个路由数组,就像 routes 本身一样。因此,你可以根据自己的需要,不断地嵌套视图。
  • 要注意,以 / 开头的嵌套路径会被当作根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。
const router = new VueRouter({
  routes: [
    // 
    { path: '/', component: Home },
    { path: '/friend', component: Friend },
    {
      path: '/setting',
      component: Setting,
      // children 用来添加子路由,每一个路由都可以添加子路由,一个子路由对应一个子路由的出口
      children: [
        // 路径不是以/开头,会把上级路径/setting作为嵌套的路径
        // 当 /setting/login 匹配成功的时候,Login 将被渲染到 Setting 的  内部
        // router-link组件to属性的值为 /setting/login
        { path: 'login', component: Login },
        // 路径是以/开头:要注意,以 / 开头的嵌套路径会被当作根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。
        // 当 /login 匹配成功的时候,Login 将被渲染到 Setting 的  内部
        // router-link组件to属性的值为 /login
        // { path: '/login', component: login },
        { path: 'regist', component: Regist },
      ],
    },
  ],
});

带路径参数的嵌套

路由导航链接改为:

<div id="app">
  <nav id="nav-list">
    <div class="w">
      <router-link to="/">首页router-link>
      <router-link to="/friend">好友router-link>
      <router-link to="/setting/tom">设置router-link>
      <router-link to="/setting/tom/login">登录router-link>
      <router-link to="/setting/tom/regist">注册router-link>
    div>
  nav>

  
  <div class="w">
    <router-view id="view">router-view>
  div>
div>

增加SettingHome路由组件:

const Home = { template: '

首页

'
}; const Friend = { template: '

好友

'
}; const Setting = { template: '

好友

'
}; const SettingHome = { template: '
SettingHome
'
}; const Login = { template: '
登录
'
}; const Regist = { template: '
注册
'
};

此时,按照上面的配置,当你访问 /setting/tom 时,在 Settingrouter-view 里面什么都不会呈现,因为没有匹配到嵌套路由。也许你确实想在那里渲染一些东西。在这种情况下,你可以提供一个空的嵌套路径:

const routes = [
  {
    path: '/setting/:name',
    component: Setting,
    children: [
      // 当/setting/:name 匹配成功
      // SettingHome 将被渲染到 Setting 的  内部
      { path: '', component: SettingHome },

      // ...其他子路由
    ],
  },
]

嵌套的命名路由

在处理命名路由时,你通常会给子路由命名

const routes = [
  {
    path: '/setting/:name',
    component: Setting,
    // 请注意,只有子路由具有名称
    children: [{ path: '', name: 'setting', component: SettingHome }],
  },
]

这将确保导航到 /setting/:name 时始终显示嵌套路由。

在一些场景中,你可能希望导航到命名路由而不导航到嵌套路由。例如,你想导航 /setting/:name 而不显示嵌套路由。那样的话,你还可以命名父路由,但请注意重新加载页面将始终显示嵌套的子路由,因为它被视为指向路径/setting/:name 的导航,而不是命名路由:

const routes = [
  {
    path: '/setting/:name',
    name: 'setting-parent'
    component: User,
    children: [{ path: '', name: 'setting', component: SettingHome }],
  },
]

命名视图

非嵌套的命名视图

有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar (侧导航) 和 main (主内容) 两个视图,这个时候命名视图就派上用场了。

你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。

  • 如果 router-view 没有设置名字,那么默认为 default
  • 如果 router-view 有名字,则使用name属性设置视图的名字
<div id="app">
  <nav id="nav-list">
    <div class="w">
      <router-link to="/">首页router-link>
      <router-link to="/friend">好友router-link>
      <router-link to="/setting">设置router-link>
    div>
  nav>

  <div class="w">
     
    <router-view class="view left-siderbar" name="LeftSidebar">router-view>
     
    <router-view class="view main-content">router-view>
    <router-view class="view right-sidebar" name="RightSidebar">router-view>
  div>
div>

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

const home = { template: '
首页
'
}; const friend = { template: '
好友
'
}; const MainContent = { template: '
主要内容
'
}; const LeftSidebar = { template: '
左侧边导航
'
}; const RightSidebar = { template: '
右侧边导航
'
}; const router = new VueRouter({ routes: [ { path: '/', component: home }, { path: '/friend', component: friend }, { path: '/setting', // 匹配命名视图的组件 components: { default: MainContent, LeftSidebar, RightSidebar, }, }, ], });

嵌套命名视图

我们也有可能使用命名视图创建嵌套视图的复杂布局。这时你也需要命名用到的嵌套 router-view 组件。我们以一个设置面板为例:

/settings/emails                                       /settings/profile
+-----------------------------------+                  +------------------------------+
| UserSettings                      |                  | UserSettings                 |
| +-----+-------------------------+ |                  | +-----+--------------------+ |
| | Nav | UserEmailsSubscriptions | |  +------------>  | | Nav | UserProfile        | |
| |     +-------------------------+ |                  | |     +--------------------+ |
| |     |                         | |                  | |     | UserProfilePreview | |
| +-----+-------------------------+ |                  | +-----+--------------------+ |
+-----------------------------------+                  +------------------------------+
  • Nav 只是一个常规组件。
  • UserSettings 是一个视图组件。
  • UserEmailsSubscriptionsUserProfileUserProfilePreview 是嵌套的视图组件。

注意:我们先忘记 HTML/CSS 具体的布局的样子,只专注在用到的组件上。

UserSettings 组件的