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;
    });
  });
};

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章