「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战」
模拟 VueRouter 的 hash 模式的实现
模拟 VueRouter 的 hash 模式的实现,实现思路和 History 模式类似,把 URL 中的 # 后面的内容作为路由的地址,可以通过 hashchange 事件监听路由地址的变化。
vue-router是什么?
官方定义:是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。
Hash模式
- URL中#后面的内容作为路径地址
- 监听hashchange事件
- 根据当前路由地址找到对应组件重新渲染
VueRouter一个对象实例,所以VueRouter为一个构造函数或者一个类,我们以类的方式来实现,VueRouter这个类里面有
个静态的install方法,里面传入了一个对象的形式,里面传入了路由的路径及对应的组件,然后在main.js中创建Vue实例,
传入router对象。
类图构造
完整代码
let _vue = null;
export default class Router {
$options = null;
routeMap = null;
data = null;
// Vue.use 方法会调用对应组件的 install 方法
static install(Vue) {
// 1. 判断插件是否被安装
if (Router.install.installed) {
return;
}
Router.install.installed = true;
// 2. 将`install`方法中的参数`vue`插入到全局中
_vue = Vue;
// 3. 将创建`vue`实例时候传入的`Router`对象注入到`vue`实例上
// 使用混入
_vue.mixin({
beforeCreate() {
if (this.$options.router) {
_vue.prototype.$router = this.$options.router;
this.$options.router.init();
}
},
});
}
constructor(options) {
// 记录构造函数中传入的选项
this.options = options;
// 将来将options的规则解析到 routeMap中来,键值对的形式
this.routeMap = {};
// data是响应式的对象,使用vue的提供的方法,方便之后路由更新我们可以及时更新页面
this.data = _vue.observable({
current: "/",
});
}
/**
* @description 注册初始化方法
*/
init() {
this.createRouteMap();
this.initComponents(_vue);
this.initEvent();
}
/**
* @description 遍历路由规则,把路由规则解析成键值对的形式,储存到routeMap中
*/
createRouteMap() {
this.options.routes.forEach((route) => {
this.routeMap[route.path] = route.component;
});
}
/**
*
* @param {*} vue 的实例
*/
initComponents(vue) {
const self = this;
vue.component("router-link", {
props: {
to: String,
},
// template: '<a :href="to"><slot></slot></a>',
render(h) {
return h(
"a",
{
attrs: {
href: "#" + this.to,
},
on: {
click: this.clickHander,
},
},
[this.$slots.default]
);
},
methods: {
clickHander(e) {
history.pushState({}, "#", this.to);
this.$router.data.current = "#" + this.to;
e.preventDefault();
},
},
});
vue.component("router-view", {
render(h) {
// 我们需要先找到当前的路由地址 self.data.current
// 找到对应路由所对应的组件
const component = self.routeMap[self.data.current];
// h函数可以将我们的路由转换成虚拟dom传递给页面
return h(component);
},
});
}
initEvent() {
window.addEventListener("hashchange", this.onHashChange.bind(this));
window.addEventListener("load", this.onHashChange.bind(this));
}
onHashChange() {
//当路由地址发生变化,重新记录当前的路径
this.data.current = window.location.hash.substr(1) || "/";
}
}