Vue-Router原理分析-路由模式和install

??单页应用(SPA, Single Page Application)的整个Web系统由一个html文件,通过Ajax和后端进行数据交互,通过一些特殊手段去加载渲染页面的不同部分,使得无需刷新整体页面,,就像使用app一样,极大的提升了用户使用体验,在Vue生态中,就是利用Vue的核心插件-Vue-Router来实现Web界面的路由跳转,so,本文就是通过学习Vue-Router,了解Vue-Router完成SPA开发的实现具体原理。

Web路由简介

??先简单说一下路由,早期Web系统路由主要是服务器后端实现,熟悉前后端开发的朋友就知道,在服务器端,通过路由表映射到相应的方法,并执行相应的动作,比如我们想要请求API数据、新页面、文件等:


"/" -> goHtml()

"/api/users" -> queryUsers()

??客户端实现路由主要就有两种方式:

1. 基于Web Url的hash
2. 基于Hishtory API

基于Web Url的hash

?? Url中的hash值是“#”号后面的参数值,比如http://www.example.com/index.html#location1里面的值localtion1, 主要有如下一些特性(之前看到公司项目的Url中带有“#”,虽然有点莫名,但都没去想想咋来的,汗):

1. Url中#后的内容不会发送到服务器;
2. hash值的改变会保存到浏览器的历史浏览记录中,可通过浏览器的回退按钮查看;
3. hash值是可读写的,可通过window.location.hash获取到hash值,利用onhashchange监听hash值的变化(Vue-Router里的hash模式就是在onhashchange中的回调事件中完成路由到界面的更新渲染)。

基于Hishtory API

??基于hash模式虽然方便,但带有#号,有同学就会觉这样的Url有点丑啦,为了和同向服务器后端请求的Url风格保持一致,就可以使用Hishtory API模式了。使用基于Hishtory API主要是操作HTML5提供的操作浏览器历史记录API,可以实现地址无刷新更新地址栏,例如:

// pushState  state: 用于描述新记录的一些特性。
// 这个参数会被一并添加到历史记录中,以供以后使用。
// 这个参数是开发者根据自己的需要自由给出的。
// pushState作用相当于修改“#”后面的值
window.history.pushState(state, "title", "/userPage");
// 比如浏览器后退
window.addEventListener("popstate", function(e) {
    var state = e.state;
    // do something...
});
// 与pushState相对仅进行Url替换而不产生新的浏览记录的replaceState方法
window.history.replaceState(null, null, "/userPage");

两种模式对比

??我们来简单对比一下这两种模式的一些特点:

模式 VS hash Hishtory API
美观程度 公认略丑,带#号 相对美观
兼容性 需要浏览器支持HTML5
错误URL后端支持

??所以两种模式的使用要根据实际项目的需求来定了,接下来是重点啦,Vue-Router内部实现路由就是基于这两种模式!所以提前了解一下前端路由的两种模式算是打个预防针。

Vue-Router

?? 先回忆一下Vue-Router的使用的四步曲,:

import Vue from 'vue';
import VueRouter from 'vue-router'
// 1. 使用Vue-Router插件
Vue.use(VueRouter)
// 2. VueRouter实例化
const router = new VueRouter({
  model: 'history', // 路由模式 hash\history
  routes: [
    {
      name: 'xx',
      path: 'path',
      component: component
    }
  ]
});
// 3. 实例化Vue实例时使用该router路由
new Vue({
  ...
  router,
});

// 4. 通过Vue.$router.push('xx') 或 router-link进行路由跳转

??接下来,就逐次窥探上面四步曲中Vue-Router具体的一些实现细节。

使用Vue-Router插件

??Vue-Router遵循Vue插件的开发规范,通过调用Vue内部方法Vue.use()对VueRouter进行install(实际上是回调VueRouter中所定义的install方法),这一过程完成了VueRouter的挂载工作。

-> vue\src\core\global-api\use.js
Vue.use = function (plugin: Function | Object) {
  ...
  plugin.install.apply(plugin, args);
  ...
}

??回到VueRouter源码中,分析一下install过程的执行流程:

import View from './components/view'
import Link from './components/link'

export let _Vue

// install实现
export function install (Vue) {

  // 如果已注册实例,则返回
  if (install.installed && _Vue === Vue) return
  install.installed = true

  _Vue = Vue 

  const isDef = v => v !== undefined

  const registerInstance = (vm, callVal) => {
    // 父虚拟节点
    let i = vm.$options._parentVnode
    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
      i(vm, callVal)
    }
  }

  Vue.mixin({
    // 路由钩子函数,在vue执行beforeCreate钩子函数回调时会一起调用,因为beforeCreate是一个数组
    beforeCreate () {
      Vue.$options = options
      if (isDef(this.$options.router)) {
        this._routerRoot = this
        this._router = this.$options.router
        // 调用init
        this._router.init(this)
        // 调用Vue内部util方法使得当前的url实现响应式化
        Vue.util.defineReactive(this, '_route', this._router.history.current)
      } else {
        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
      }
      // 注册实例
      registerInstance(this, this)
    },
    destroyed () {
      registerInstance(this)
    }
  })
  // 将$router和$route挂载到Vue的原型链上
  Object.defineProperty(Vue.prototype, '$router', {
    get () { return this._routerRoot._router }
  })

  Object.defineProperty(Vue.prototype, '$route', {
    get () { return this._routerRoot._route }
  })

  // 注册路由视图和路由链接两个组件
  Vue.component('RouterView', View)
  Vue.component('RouterLink', Link)

  // 执行Vue的选项合并策略
  const strats = Vue.config.optionMergeStrategies
  // use the same hook merging strategy for route hooks
  strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}

??可以看出,在install内部主要做了三个事:

    1. 就是利用Vue的mixin方法混入了全局beforeCreate和destoryed,在首次加载执行beforeCreate时,指定_routerRoot为当前的Vue实例,并且执行Vue-Router的init初始化工作(install最核心还是init初始化,这个具体细节稍后进行介绍),在beforeCreate方法内,主要是对父组件(也就是router所挂载的节点)进行初始化操作,并设置当前的_routerRoot为该组件对应的实例,在该逐渐中去初始化init路由的一些配置(比如设置路由模式等),其他组件比如(router-link, router-view会将_routerRoot设置为在options参数中包含了router选项的父(祖先)组件),并执行registerInstance方法,该方法中的registerRouteInstance目前其实是router-view组件中所定义的一个方法,主要作用是执行当前组件的渲染工作,如下:
const registerInstance = (vm, callVal) => {
    // 父虚拟节点
    let i = vm.$options._parentVnode
    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
      i(vm, callVal)
    }
  }

??这个混入相当于是定义,具体执行时等各组件在进行实例化时按照生命周期回调beforeCreate和destoryed这两个钩子函数,destroyed作用是在进行比如路由切换后、实际上作用就是清除上一个展示在router-view中的组件所渲染的内容。

    1. 将$router和$route挂载到Vue的原型链上,可以通过this.$router和this.$route进行使用;
    1. 注册router-link和router-view两个组件到Vue中。

总结

??由于希望篇幅不要太大,不然看起来比较吃力,所以本篇文章先就写到这里,关于实例化和具体使用所涉及到的原理工作后面文章再讨论。在这对本篇文章做一个小结:

  • 简要介绍了前端路由,以及实现前端路由的两种模式 URL hash和history API并对这两者做了对比;
  • 介绍了Vue是如何use Vue-Router组件,实际上内部就是回调Vue-Router内部定义的install方法;
  • 介绍了install方法的一些主要工作职能:
    • 混入beforeCreate和destoryed方法;
    • 全局挂载$router和$route;
    • 注册router-link和router-view两个组件。
      另外,欢迎去本人git 可相互学习和star。

原文地址:https://www.cnblogs.com/boykait/p/11106437.html

时间: 2024-08-25 06:22:36

Vue-Router原理分析-路由模式和install的相关文章

虚拟 ?router 原理分析- 每天5分钟玩转 OpenStack(101)

上一节我们创建了虚拟路由器"router_100_101",并通过 ping 验证了 vlan100 和 vlan101 已经连通. 本节将重点分析其中的原理. 首先我们查看控制节点的 linux bridge 结构发生了什么变化. vlan101 的 bridge 上多了一个 tape17162c5-00,从命名上可以推断该 TAP 设备对应 router_100_101 的 interface (e17162c5-00fa). vlan100 的 bridge 上多了一个 tapd

四、Vue Router 设置动态路由

动态路由配置 像/user/foo和/user/bar都映射到相同的路由.也就是说根据不同的ID,渲染相同的User组件.可以使用动态路径参数来达到这个效果. 动态路径参数使用冒号:标记,后面为参数的名称,参数会被设置到this.$route.params中. <script> // 匹配模式 /user/:username // 匹配到的路径为 /user/evan // $route.params 获取到的参数对象 { useranme: 'evan' } </script>

(尚039) Vue_router路由模式

说明: 1) 官方提供的用来实现 SPA 的 vue 插件 2) github: https://github.com/vuejs/vue-router 3) 中文文档: http://router.vuejs.org/zh-cn/ 4) 下载: npm install vue-router --save ================================================== 1.路由器与路由的概念区别? 路由器不是路由,是两种不同的概念; 路由器管理路由; 2.什

04 Vue Router路由管理器

路由的基本概念与原理 Vue Router Vue Router (官网: https://router.vuejs.org/zh/)是Vue.js 官方的路由管理器. 它和vue.js的核心深度集成,可以非常方便的用于SPA应用程序的开发. Vue Router包含的功能有: 支持HTML5 历史模式或hash模式 支持嵌套路由 支持路由参数 支持编程式路由 支持命名路由 vue-router的基本使用 基本使用步骤 1.引入相关的库文件 导入vue文件为全局window对象挂载Vue构造函数

Vue系列:Vue Router 路由梳理

Vue Router 是 Vue.js 官方的路由管理器.它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌.包含的功能有: 嵌套的路由/视图表 模块化的.基于组件的路由配置 路由参数.查询.通配符 基于 Vue.js 过渡系统的视图过渡效果 细粒度的导航控制 带有自动激活的 CSS class 的链接 HTML5 历史模式或 hash 模式,在 IE9 中自动降级 自定义的滚动条行为 1.动态路由 动态路由,可以将某种模式匹配到的所有路由,并全都映射到同个组件. (通俗点,比如根

Vue.js路由管理器 Vue Router

起步 HTML <script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> <div id="app"> <h1>Hello App!</h1> <p>

vue 中的路由为什么 采用 hash 路由模式,而不是href超链接模式(Hypertext,Reference)?

1. vue中路由模式的种类有两种 1. 一种是 hash 模式. 2. 一种是 h5 的 history 模式. 2. hash 和 history 都是来自 bom 对象 bom 来自 window 3. window.location.hash 4. hash 是属于 window.location 这个对象,而history直接属于 window 5. window.history 6. 是因为路由模式下,当hash值发生改变,不会发生网络请求,但是href会,vue会自动监听hash

[Vue源码分析] v-model实现原理

最近小组有个关于vue源码分析的分享会,提前准备一下- 前言:我们都知道使用v-model可以实现数据的双向绑定,及实现数据的变化驱动dom的更新,dom的更新影响数据的变化.那么v-model是怎么实现这一原理的呢?接下来探索一下这部分的源码. 前期准备①:vue2.5.2源码(用于阅读.查看关联等)②:建立vue demo,创建包含v-model指令的实例(用于debugger)以下为demo: genDirectives在模板的编译阶段, v-model跟其他指令一样,会被解析到 el.d

Vue Router 路由守卫:完整的导航解析流程

完整的导航解析流程 1 导航被触发. 2 在失活的组件里调用离开守卫. 3 调用全局的 beforeEach 守卫. 4 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+). 5 在路由配置里调用 beforeEnter. 6 解析异步路由组件. 7 在被激活的组件里调用 beforeRouteEnter. 8 调用全局的 beforeResolve 守卫 (2.5+). 9 导航被确认. 10 调用全局的 afterEach 钩子. 11 触发 DOM 更新. 12 用