Vue-Router 源码解析 Vue内this.$router和this.$route的区别

Posted greatdesert

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue-Router 源码解析 Vue内this.$router和this.$route的区别相关的知识,希望对你有一定的参考价值。

对于Vue内部来说,不管是根组件还是子组件,都存在this.$router和this.$route两个属性,它们的区别如下:

$router    指向当前的VueRouter实例,也就是new Vue({router:router})这里传入的router实例对象,可以使用上一节里列出的VueRouter实例的属性和方法

$route       指向当前跳转的路由对象,是一个包含当前的路由信息的对象,<router-view/>组件会通过这个属性来获取需要渲染的组件

对于$router来说,它包含了如下属性

  • path            ;当前路由的路劲,总是解析为绝对路劲        ;例如:/foo/bar
  • params        ;对象类型,包含了动态片段和全匹配片段,如果没有路由参数就是一个空对象
  • query            ;对象类型,表示URL查询参数,对于/foo/user=1来说,$route.query.user等于1,如果没有查询参数,则是个空对象
  • hash            ;当前路由的hash值(带#),如果没有hash值,则为空字符串
  • fullPath        ;解析完成后的URL,包含查询参数和hash的完整路劲
  • matched        ;一个数组,包含当前路由的所有嵌套路劲片段的路由记录,也就是所有父路由对象都在这个数组里面,<router-view/>组件会用到这个属性
  • name            ;当前路由的名称            ;和命名别名有关
  • redirectedFrom    ;重定向来源的路由的名字        ;和重定向及别名有关。
  • meta            ;meta值

name、meta这两个值就是创建vuerouter时,传入的router属性对应的每条路由记录的name和mata属性,其它的一般经过一些处理

 writer by:大沙漠 QQ:22969969

举个栗子:

    <div id="app">
        <router-link to="/login">登陆</router-link>
        <router-link to="/info/15">详情页</router-link>     
        <hr/>
        <router-view></router-view>
    </div>
    <script>
        const login = { template:<div>Login Page!</div>}                       
        const info  = { template:<div>id:{{this.$route.params.id}}</div>}
        const routes = [                                                       
            {path:/login,component:login,name:login},
            {path:/info/:id,component:info,name:info},
        ]
        const app = new Vue({                                                     
            el:#app,
            router:new VueRouter({routes})
        })
    </script>

渲染如下:

技术图片

我们点击登陆路由到登陆页面,控制台输入app.$route,然后点击详情页,控制台再输入app.$route,打印分别如下:

Login页面:技术图片 Info页面:技术图片

经常用到这个$route对象的地方就是在导航守卫里,参数2的to就是这个$route对象。

VueRouter安装的时候会执行它的install方法,该方法如下:

Object.defineProperty(Vue.prototype, ‘$router‘, {                 //Vue实例的$router指向了this._routerRoot._router
    get: function get () { return this._routerRoot._router }
});

Object.defineProperty(Vue.prototype, ‘$route‘, {                 //设置$route为this.$root._route
    get: function get () { return this._routerRoot._route }
});

通过执行Object.defineProperty,我们在Vue内部访问this.$router和this.$route都一直指向了this._routerRoot._router和this._routeRoot._route,而这两个属性是在VueRouter在安装的时候混入到Vue的beforeCreate生命周期函数内实现的,如下:

beforeCreate: function beforeCreate () {
  if (isDef(this.$options.router)) {             //如果this.$options.router存在    ;就是在创建Vue实例时传入的router对象
    this._routerRoot = this;                         //在Vue实例上添加一个_routerRoot指向自己,即Vue实例
    this._router = this.$options.router;             //在Vue实例上添加一个_router指向构造时的vue-router实例
    this._router.init(this);                         //vue-router实例调用init()进行初始化,参数为Vue实例
    Vue.util.defineReactive(this, ‘_route‘, this._router.history.current);         //通过Vue的defineReactive把_router变成响应式,等于this._router.history.current
  } else {
    this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;
  }
  registerInstance(this, this);
},

this._router.history.current等于VueRouter实例.history.current属性,在每次路由跳转后都会执行History原型上的updateRoute方法,会在该方法内重置current属性,路由对象的创建如下:

    function createRoute(record, location, redirectedFrom, router) {    //创建一个路由对象 record:路由记录信息 location:需要跳转的路由地址(包含path、query、hash和params的对象)  redirectedForm:未知 router:Vue-Router实例
        var stringifyQuery$$1 = router && router.options.stringifyQuery;

        var query = location.query || {};                                   //重置query,如果未设置则重置为空对象
        try {
            query = clone(query);
        } catch (e) {}

        var route = {                                                       //添加一个route对象
            name: location.name || (record && record.name),                     //name信息
            meta: (record && record.meta) || {},                                //meta信息
            path: location.path || ‘/‘,
            hash: location.hash || ‘‘,                                          //路由的路劲
            query: query,                                                       //路由的hash
            params: location.params || {},                                      //路由的params
            fullPath: getFullPath(location, stringifyQuery$$1),                 //完整路劲
            matched: record ? formatMatch(record) : []                          //记录record 从当前到父节点一直到祖先节点的所有record
        };
        if (redirectedFrom) {
            route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery$$1);
        }
        return Object.freeze(route)                                         //最后将route对象冻结并返回(即不允许新增属性)
    }

以上是关于Vue-Router 源码解析 Vue内this.$router和this.$route的区别的主要内容,如果未能解决你的问题,请参考以下文章

浅读vue-router源码,了解vue-router基本原理

Vue-Router 源码解析 router-link组件的用法及原理

大白话理解前后端路由+vue-router源码

vue-router的钩子函数

解析Vue-router相关干货及工作原理

vue 组件无法从 vue-router 获取 this.$router