Vue-Router探索

介绍

vue-router是一个vue插件。其实质是在location.hash、location.replace、HTML5 historyAPI、window.onpopstate、window.onhashchange上做的封装,通过一定的规则映射到对应的方法上,同时通过监听变化,从而实现单页路由。


装载

使用use(VueRouter)注入Vue中,use方法会检测注入插件VueRouter内的install方法(浏览器环境会自动调用,node环境需要手动调用)

第一步:Install解析(对应目录结构的install.js)
该方法内主要做了以下三件事:

  1. 对Vue实例混入beforeCreate钩子操作(在Vue的生命周期阶段会被调用)
  2. 通过Vue.prototype定义router、route 属性(方便所有组件可以获取这两个属性)
    注:$route为当前router跳转对象里面可以获取name、path、query、params等(只读)
    $router为VueRouter实例,想要导航到不同URL,则使用$router.push方法
  3. Vue上注册router-link和router-view两个组件

第二步:生成router实例
生成实例过程中,主要做了以下两件事

  1. 根据配置数组(传入的routes)生成路由配置记录表。(根据传入的 routes 配置生成对应的路由 map,然后直接返回了 match 匹配函数)
  2. 根据不同模式生成监控路由变化的History对象
    注:History类由HTML5History、HashHistory、AbstractHistory三类继承,默认为hash模式

history/base.js实现了基本history的操作
history/hash.js,history/html5.js和history/abstract.js继承了base,只是根据不同的模式封装了一些基本操作

第三步:生成vue实例
进入Vue的生命周期,第一步Vue-Router对Vue混入的beforeCreate钩子会执行。
一开始验证vue是否有router对象了,如果有,就不再初始化了。否则,先将routerRoot指向根组件,将router对象挂载到根组件元素_router上(this._routerRoot = this; this._router = this.$options.router)然后初始化,建立路由监控,劫持数据_route,一旦_route数据发生变化后,通知router-view执行render方法。
三步走完初始化结束,界面将显示默认首页。

关系图

文件结构

vue-router src文件结构

components下是两个组件router-view和router-link;history是路由方式的封装,提供三种方式;util下主要是各种功能类和功能函数;create-matcher和create-router-map是生成匹配表;index是VueRouter类,也整个插件的入口;Install 提供安装的方法


路由更新触发方式

一、主动触发

router-link绑定了click方法,触发history.push或者history.replace,从而触发history.transitionTo。(这里的history并不是H5的History对象,而是vue-router里定义的history对象)

transitionTo用于处理路由转换,其中包含了updateRoute用于更新_route。

在beforeCreate中有劫持_route的方法,当_route变化后,触发router-view的变化。

二、地址变化(如:在浏览器地址栏直接输入地址)

HashHistory和HTML5History会分别监控hashchange和popstate来对路由变化作对用的处理 。

HashHistory和HTML5History捕获到变化后会对应执行push或replace方法,从而调用transitionTo,剩下的就和上面主动触发一样啦。


路由更新详解

在使用单页面前端路由跳转时,提供了两种方式:Hash模式History模式
那为什么这两种方式能够实现试图更新不跳转,其原因在于:

1、Hash模式
hash(#)是URL 的锚点,代表的是网页中的一个位置,单单改变#后的部分,浏览器只会滚动到相应位置,不会重新加载网页,也就是说 #是用来指导浏览器动作的,对服务器端完全无用,HTTP请求中也不会不包括#;同时每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置。
(hash虽然出现在URL中,但不会被包括在HTTP请求中。它是用来指导浏览器动作的,对服务器端完全无用,因此,改变hash不会重新加载页面)

HashHistory.push()流程:$router.push() --> HashHistory.push() --> History.transitionTo() --> History.updateRoute() --> vm.render() (调用window.location.hash修改)

HashHistory.replace() 实现基本与push类似,不同之处在于,它并不是将新路由添加到浏览器访问历史的栈顶,而是调用window.location.replace替换掉当前的路由

另外,HashHistory通过setupListeners,设置监听了浏览器事件hashchange来应对用户直接在地址栏输入改变路由,调用的函数为replaceHash,即在浏览器地址栏中直接输入路由相当于代码调用了replace()方法

2、History模式

HTML5 History API提供了一种功能,能让开发人员在不刷新整个页面的情况下修改站点的URL,就是利用 history.pushState API 来完成 URL 跳转而无须重新加载页面;

3、抽象模式

抽象模式是属于最简单的处理了,因为不涉及和浏览器地址相关记录关联在一起;整体流程依旧和 HashHistory 是一样的,只是这里通过数组来模拟浏览器历史记录堆栈信息。


Hash模式和History模式比较

除了#比较丑外,调用history.pushState()相比于直接修改hash的优势有:

  1. pushState设置的新URL可以是与当前URL同源的任意URL;而hash只可修改#后面的部分,故只可设置与当前同文档的URL
  2. pushState设置的新URL可以与当前URL一模一样,这样也会把记录添加到栈中;而hash设置的新值必须与原来不一样才会触发记录添加到栈中
  3. pushState通过stateObject可以添加任意类型的数据到记录中;而hash只可添加短字符串
  4. pushState可额外设置title属性供后续使用

问题? 因为hash模式仅改变hash部分的内容,而hash部分是不会包含在HTTP请求中的:
http://oursite.com/#/user/id // 如重新请求只会发送http://oursite.com/故在hash模式下遇到根据URL请求页面的情况不会有问题。

而history模式则会将URL修改得就和正常请求后端的URL一样http://oursite.com/user/id会报404error,这个时候需要vue应用覆盖所有情况给出一个404页面或者是node作后台的话中间过滤一层


匹配优先级

有时候,同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高


关于守卫**

参数或查询的改变并不会触发进入/离开的导航守卫。不会应用在跳转路由上,而仅仅应用在其目标上。为redirect前的/a路由添加一个beforeEach或beforeLeave守卫并不会有任何效果。

  • 全局守卫beforeEach 当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中

  • 全局解析守卫beforeResolve 和router.beforeEach类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。

  • 全局后置钩子afterEach和守卫不同的是,这些钩子不会接受next函数也不会改变导航本身。

  • 路由独享的守卫beforeEnter 与全局前置守卫的方法参数是一样的,在路由配置上直接定义,直接写在路由配置里面。

  • 组件内的守卫 beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave

完整流程:
1.导航被触发
2.在失活的组件里调用离开守卫
3.调用全局的beforeEach守卫
4.在重用的组件里调用beforeRouteUpdate守卫
5.在路由配置里调用beforeEnter
6.解析异步路由组件
7.在被激活的组件里调用beforeRouteEnter
8.调用全局的beforeResolve守卫
9.导航被确认
10.调用全局的afterEach钩子
11.触发 DOM 更新
12.用创建好的实例调用beforeRouteEnter守卫中传给next的回调函数。


比较Vue-router与React-router

他们最基本的初衷都是实现前端路由。所谓前端路由,简单来说,就是当浏览器的url产生变化时,不向服务器进行请求,而是直接控制前端页面产生变化,以期待前端在比如功能切换时,产生类似页面跳转等效果。

而这里面最基本的,无论是vue-router还是react-router,都要提供一种配置方式,让使用者可以配置出url路径和要展示的组件的对应关系。让其在用户更改url时通过这个url找到对应的组件,从而有针对性的在页面上渲染。

需要注意的是:VUE的路由配置要提供给new VueRouter()对象,这个对象要在全局VUE对象初始化时提供;而React路由则需要配置给全局<Router>组件,虽然react-router也提供类似于vue-router典型代码中的对象数组形式的配置方式,但是最终仍是要将配置传递给<Router>。一个是全局配置(VUE),一个是全局组件(React),这是两者使用上的根本区别之一。(vue-router并不提供像JSX这种类html的配置方式,它只能以对象方式提供路由配置,这也是框架系统不同所决定的)

总结不同:

  • vue-router是全局配置方式,react-router是全局组件方式。

  • vue-router仅支持对象形式的配置,react-router支持对象形式和JSX语法的组件形式配置。

  • vue-router任何路由组件都会被渲染到<router-view>位置,react-router子组件作为children被传入父组件,而根组件被渲染到<Router>位置。


参考

原理分析
源码详细分析

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

推荐阅读更多精彩内容