简版vue-router源码
hash模式
let Vue; export default class VueRouter { constructor(options) { this.$options = options; this.routerMap = {}; this.initRouterMap(); // 定义一个响应式的current,则如果他变了,那么使用它的组件会rerender Vue.util.defineReactive(this, "current", ""); window.addEventListener("hashchange", this.onHashChange.bind(this)); window.addEventListener("load", this.onHashChange.bind(this)); } onHashChange() { this.current = window.location.hash.slice(1) || "/"; } initRouterMap() { this.$options.routes.forEach((route) => { this.routeMap[route.path] = route.component; });
} } VueRouter.install = function (_Vue) { Vue = _Vue; Vue.mixin({ beforeCreate() { if (this.$options.router) { Vue.prototype.$router = this.options.router; } }, }); Vue.component("router-link", { props: { to: { type: String, required: true, }, }, render(h) { return h( "a", { attrs: { href: this.to, }, }, [this.$slot.default] ); }, });
const self = this; Vue.component("router-view", { render(h) { let component = null; const { routeMap, current } = self.$router; if (routeMap[current]) { component = routeMap[current]; } return h(component); }, });
};
history模式:
let Vue; export default class VueRouter { static install(_Vue) { // 如果已经安装过则不再往下执行 if (VueRouter.install.installed) { return; } VueRouter.install.installed = true; Vue = _Vue; Vue.mixin({ beforeCreate() { if (this.$options.router) { Vue.prototype.$router = this.$options.router; } }, }); } constructor(options) { this.$options = options; this.routeMap = {}; Vue.util.defineReactive(this, "current", "/"); } init() { this.initRouterMap(); this.initComponents(Vue); this.initEvent(); } initRouterMap() { // 遍历所有的路由规则,把路由规则解析成键值对的形式 存储到 routeMap 中 this.$options.routes.forEach((route) => { this.routeMap[route.path] = route.component; }); } initEvent() { window.addEventListener("popstate", () => { this.current = window.location.pathname; }); } initComponents(Vue) { Vue.component("router-link", { props: { to: { type: String, required: true, }, }, render(h) { return h("a", { attrs: { href: this.to, }, on: { click: this.handleClick, }, }); }, methods: { handleClick(e) { e.preventDefault(); history.pushState({}, "", this.to); this.current = this.to; }, }, }); const self = this; Vue.component("router-view", { render(h) { const component = self.routeMap[self.current]; return h(component); }, }); } }