手写vue-router
定义2个类 VueRoutr、 HistoryRouter
1、new VueRouter 传入options
2、判断路由模式
3、通过window监听hashchange的改变,截取当前路由的hash值,并把存到当前的hash值存到HistoryRouter实例中
let Vue = null;
class HistoryRoute {
constructor() {
this.current = null; // 记录当前路由
}
}
class VueRouter {
constructor(options) {
this.mode = options.mode || 'hash';// 记录router的模式
this.routes = options.routes || []; // 记录路由表
this.history = new HistoryRoute(); // 记录当前路由
this.routesMap = this.createMap(this.routes); // 将路由表转换成键值对
// 初始化路由
this.init();
}
// 初始化路由
init() {
// hash模式
if(this.mode === 'hash'){
location.hash ? '' : location.hash = '/';
// 监听页面重新加载,将当前路由赋值给history.current
window.addEventListener('load', () => {
this.history.current = location.hash.slice(1);
})
// 监听hash值变化,将当前路由赋值给history.current
window.addEventListener('hashchange', () => {
this.history.current = location.hash.slice(1);
} )
} else {
// 待定问题
}
}
// 将路由表变成键值对
createMap (routers) {
const map = routers.reduce((pre, current) => {
pre[current.path] = current.component;
return pre
},{})
debugger
return map
}
}
实现 VueRouter.install函数
-
用混入, 在组件生成前(beforeCreate中) 把当前路由变成响应式的(如果当前路由hash值改变时, 全局组件router-view会重新获取新path对应的组件,并进行渲染)
-
在组件生成前(beforeCreate中) 实现
$router 和 $route -
注册全局组件 router-link
-
注册全局组件 router-view
VueRouter.install = function (v) {
Vue = v;
// 混入
Vue.mixin({
beforeCreate() {
if (this.$options && this.$options.router){
// 根组件
this._root = this;
this._router = this.$options.router;
// 将当前路由变成响应式的
Vue.util.defineReactive(this, 'xxx', this._router.history)
} else {
// 子组件
this._root = this.$parent && this.$parent._root;
this._router = this.$parent && this.$parent._router;
}
// this.$router.push('/home');
Object.defineProperty(this, '$router', {
get() {
return this._router
}
})
// 返回当前路由
Object.defineProperty(this, '$route', {
get() {
return this._router.history.current
}
})
}
});
// 注册全局组件 router-link
Vue.component('router-link', {
props: {
to: String
},
render(h) {
return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default)
},
})
// 注册全局组件 router-view
Vue.component('router-view', {
render(h) {
const current = this._self._root._router.history.current;
const routesMap = this._self._root._router.routesMap
return h(routesMap[current])
}
})
}