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