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