vue-router源码浅显分析(一)--Vue.use(VueRouter), new VueRouter(options)

1,vue中使用vueRouter是通过vue.use(vueRouter),use方法调用了VueRouter的install方法

if (install.installed && _Vue === Vue) { return }
  install.installed = true;

  _Vue = Vue;

  var isDef = function (v) { return v !== undefined; };

  var registerInstance = function (vm, callVal) {
    var i = vm.$options._parentVnode;
    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
      i(vm, callVal);
    }
  };

       构造实例new Vue({router})时,传入router对象(router = new vueRouter(routerConfig))router被挂载到vue的this.$options属性上 划重点:this._router.init(this)

Vue.mixin({
    beforeCreate: function beforeCreate () {
      if (isDef(this.$options.router)) {
        this._routerRoot = this;
        this._router = this.$options.router;
        this._router.init(this);
//调用vue.util里的方法,通过get和set劫持this._route,router-view实时更新
        Vue.util.defineReactive(this, '_route', this._router.history.current);
      } else {
        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;
      }
//router-view的render方法里定义了data.registerRouteInstance方法
      registerInstance(this, this);
    },
    destroyed: function destroyed () {
      registerInstance(this);
    }
  });

  Object.defineProperty(Vue.prototype, '$router', {
    get: function get () { return this._routerRoot._router }
  });

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

         通过Vue.mixin()在beforeCreate中初始了this._routerRoot._router 和this._routerRoot._route,并分别赋值给Vue.prototype的$router, $route属性。于是就有了,this.$router和this.$route对象可以使用。

Vue.component('router-view', View);

Vue.component('router-link', Link);

  给vue创建了组件router-view和router-link      

var strats = Vue.config.optionMergeStrategies;
  // use the same hook merging strategy for route hooks
  strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created;

定义了组件内的路由钩子,默认跟created方法一样

所以 install方法中,主要做了三件事情,在beforeCreate中挂载上路由,定义router和route, 注册router-view、router-link组件

2,router = new vueRouter(routerConfig) 实例化时

var VueRouter = function VueRouter (options) {
  if ( options === void 0 ) options = {};

  this.app = null;
  this.apps = [];
  this.options = options;
  this.beforeHooks = [];
  this.resolveHooks = [];
  this.afterHooks = [];
//调用createRouteMap方法,遍历routes,执行addRouteRecord(递归)生成的record对象存入
//pathList pathMap nameMap。

//createRouteMap最后 return { pathList: pathList, pathMap: pathMap, nameMap: nameMap }
  this.matcher = createMatcher(options.routes || [], this);

  var mode = options.mode || 'hash';
//如果当前环境不支持history模式,强制切换到hash模式
  this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false;
  if (this.fallback) {
    mode = 'hash';
  }
//如果不是浏览器环境,切换到abstract模式
  if (!inBrowser) {
    mode = 'abstract';
  }
  this.mode = mode;
//根据mode值创建不同的实例,生成不同的history对象
  switch (mode) {
    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));
      }
  }
};

根据mode给history指定实例,在init方法中有用到history的方法,回到重点this._router.init(this)方法:

VueRouter.prototype.init = function init (app /* Vue component instance */) {
    var this$1 = this;

  "development" !== 'production' && assert(
    install.installed,
    "not installed. Make sure to call `Vue.use(VueRouter)` " +
    "before creating root instance."
  );
//将当前vue实例的this存放到this.apps数组里
  this.apps.push(app);

  // main app already initialized.判断this.app是否已经被初始化过
  if (this.app) {
    return
  }
    //存储当前实例this
  this.app = app;

  var history = this.history;
//通过history类型来切换路由
  if (history instanceof HTML5History) {
    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;
    });
  });
};

猜你喜欢

转载自blog.csdn.net/haoyanyu_/article/details/87785788