欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Vue-Router 源码分析(三) VueRouter实例的属性和方法

程序员文章站 2022-04-15 14:07:57
我们首先用new VueRouter()创建一个VueRouter实例,之后在创建根Vue实例时把这个VueRouter实例作为router属性传递进去,在这个过程中一般有两种方法可以获取到该VueRouter的实例 第一种是node环境下,我们一般在项目源码的路劲下创建一个router目录,该目录 ......

我们首先用new vuerouter()创建一个vuerouter实例,之后在创建根vue实例时把这个vuerouter实例作为router属性传递进去,在这个过程中一般有两种方法可以获取到该vuerouter的实例

第一种是node环境下,我们一般在项目源码的路劲下创建一个router目录,该目录保存所有的路由配置信息,例如:

var router = new router({
  routes: [/*略*/]
})
router.foreach((to,from,next)=>{
  next();
})
export default router;

这里我们创建new router实例后可以直接对该实例进行操作,比如这里通过vuerouter实例设置了foreach导航守卫

还有一种获取vuerouter实例的地方是在vue内,我们可以通过this.$router获取到vuerouter实例:

this.$router.push('/login')

通过this.$router我们可以通过push、back等api进行路由跳转。对于vuerouter实例来说它含有如下属性和方法:

  • app          配置了router的vue根实例
  • mode            当前的路由模式,可以为hash、history或者abstract
  • options         创建vuerouter实例时传入的所有参数
  • history          当前的history对象(通过该对象进行路由跳转的)
  • addroutes   动态添加更多的路由规则,参数必须时一个符合routes选项要求的数组
  • push                      路由到新的路由地址
  • replace                 替换当前路由到新的路由(它不会向history添加新记录)
  • go                         在history记录中向前或向后退多少步
  • back                     在history记录中后退一步,等效于go(-1)
  • forward                 在history记录中前进一步,等效于go(1)
  • beforeeach                    全局前置守卫
  • beforeresolve              全局解析守卫
  • aftereach                      全局后置钩子
  • onready(callback,errorcallback)    注册两个回调函数,在路由完成初始导航时触发
  • onerror(callback)                  注册一个回调,该回调会在导航过程中出错时被调用

对于app属性来说,我们经常用到的地方就是在导航首位里可以通过router.app.$store.tokens获取当前是否有tokens,如果没有,则路由到登录页面

在vue组件内可以通过this.$router.push()等进行路由跳转,这些都是执行vuerouter实例的方法来实现的。

在vue源码内,vuerouter是一个函数对象,如下:

var vuerouter = function vuerouter (options) {      //构造函数
  if ( options === void 0 ) options = {};             //如果option为undefined,则修正为空对象

  this.app = null;
  this.apps = [];
  this.options = options;                             //保存options
  this.beforehooks = [];                              //初始化三个数组,分别对应beforeeach、beforeresolve、aftereach三个全局导航守卫的注册函数
  this.resolvehooks = [];
  this.afterhooks = [];
  this.matcher = creatematcher(options.routes || [], this);

  //初始化/修正mode
  var mode = options.mode || 'hash';
  this.fallback = mode === 'history' && !supportspushstate && options.fallback !== false;
  if (this.fallback) {
    mode = 'hash';
  }
  if (!inbrowser) {
    mode = 'abstract';
  }
  this.mode = mode;

  switch (mode) {                                     //根据不同的模式,对this.history做出实例化
    case 'history':
      this.history = new html5history(this, options.base);
      break
    case 'hash':
      this.history = new hashhistory(this, options.base, this.fallback);
      break
    case 'abstract':
      this.history = new abstracthistory(this, options.base);
      break
    default:
      {
        assert(false, ("invalid mode: " + mode));
      }
  }
};

其它的方法都是定义在vuerouter的原型对象上的,对于跳转的接口来说(push、replace、go、back、forward)来说,它们是操作this.history对象来实现跳转的。

vue初始化时会在beforecreate生命周期函数内会执行vuerrouter实例的init方法,如下:

vuerouter.prototype.init = function init (app ) {     //路由初始化,在vue实例的beforecreate生命周期时执行 app:使用了该vue-router的vue实例,页面初始化时执行到这里
    var this$1 = this;                                    //this$1指向vuerouter实例

  "development" !== 'production' && assert(
    install.installed,
    "not installed. make sure to call `vue.use(vuerouter)` " +
    "before creating root instance."
  );

  this.apps.push(app);

  // main app already initialized.
  if (this.app) {
    return
  }

  this.app = app;                                         //设置this.app等于app,也就是vue实例

  var history = this.history;                             //获取history实例

  if (history instanceof html5history) {                  //执行history.transitionto()进行路由初始化,路由初始化完成后会触发onready()注册的回调函数的。
    history.transitionto(history.getcurrentlocation());
  } else if (history instanceof hashhistory) {            
    var setuphashlistener = function () {
      history.setuplisteners();
    };
    history.transitionto(
      history.getcurrentlocation(),
      setuphashlistener,
      setuphashlistener
    );
  }

  history.listen(function (route) {
    this$1.apps.foreach(function (app) {
      app._route = route;
    });
  });
};

路由初始胡完成后就会等到<vue-link>触发相应的事件(默认为click)进行路由跳转了,或者通过push()、go()等函数式编程触发了。