Vue-Router|Vue-Router 实现原理
Hash 和 History 模式
Hash 模式
http://localhost.com/#/user/id
Hash 模式基于锚点,以及 onhashchange 事件。
- 通过
window.location.href
改动浏览器地址, 如果只改变#
后面的地址,不会触发服务端请求,会把#
后的值作为路由地址 - 当地址发生变化时触发
onhashchange
事件,监听事件并做相应处理 - 切换显示不同的组件
http://localhost.com/user/id
History 模式基于 HTML5 中的 History API
- 通过 history.pushState() 方法改变浏览器地址,只会改变浏览器地址而不会向服务端发送请求,并把当前地址记录到浏览器的历史记录中
- history.pushState():不会向服务端发送请求,pushState 会在 history 栈中添加一个新的记录
- history.replaceState(): 不会向服务端发送请求,replaceState 不会添加新的 history 栈记录,而是替换当前的url
- 监听 popstate 事件,可以监听到浏览器历史数据的变化。事情不会在 pushStash 或 replaceStash 中触发,只会在浏览器前进或回退时触发
- 根据当前路由地址找到对应组件重新渲染
location / { roothtml;
indexindex.html index.htm;
#新添加内容
#尝试读取$uri(当前请求的路径),如果读取不到读取$uri/这个文件夹下的首页
#如果都获取不到返回根目录中的 index.html try_files $uri $uri/ /index.html;
}
模拟实现
- 【Vue-Router|Vue-Router 实现原理】创建 VueRouter 插件,静态方法 install
- 判断插件是否已经被加载
- 当 Vue 加载的时候把传入的 router 对象挂载到 Vue 实列上(全局混入的目的是拿到 Vue 实列)
- 创建 VueRouter 类
- 初始化,options、routeMap、data(路径,创建 Vue 实例作为响应式数据记录当前路径)
- createRouteMap() 遍历所有路由信息,把组件和路由的映射记录到 routeMap 对象中
- initComponent() 创建 router-link 和 router-view 组件
- initEvent() 注册 popstate 事件,当路由地址发生变化,重新记录当前的路径
- 当路径改变的时候通过当前路径在 routerMap 对象中找到对应的组件,渲染 router-view
let _Vue = null;
export default class VueRouter {
constructor(options) {
this.options = options;
this.routeMap = {};
this.data = https://www.it610.com/article/_Vue.observable({
current:"/",
});
this.createRouteMap();
this.initComponent(_Vue);
this.initEvent();
}static install(Vue) {
//1 判断当前插件是否被安装
if (VueRouter.install.installed) {
return;
}
VueRouter.install.installed = true;
//2 把Vue的构造函数记录在全局
_Vue = Vue;
//3 把创建Vue的实例传入的router对象注入到Vue实例
// _Vue.prototype.$router = this.$options.router
_Vue.mixin({
beforeCreate() {
if (this.$options.router) {
_Vue.prototype.$router = this.$options.router;
}
},
});
}// 遍历所有的路由规则 吧路由规则解析成键值对的形式存储到routeMap中
createRouteMap() {
this.options.routes.forEach((route) => {
this.routeMap[route.path] = route.component;
});
}
// 创建 router-link 和 router-view 组件
initComponent(Vue) {
Vue.component("router-link", {
props: {
to: String,
},
render(h) {
return h(
"a",
{
attrs: {
href: this.to,
},
on: {
click: this.clickHandler,
},
},
[this.$slots.default]
);
},
methods: {
clickHandler(e) {
// 改变地址,不发送请求,记录地址历史
history.pushState({}, "", this.to);
this.$router.data.current = this.to;
// 阻住后续执行,不让超链接跳转
e.preventDefault();
},
},
// template:"<>"
});
const self = this;
Vue.component("router-view", {
render(h) {
const cm = self.routeMap[self.data.current];
return h(cm);
},
});
}
// 注册 popstate 事件,当路由地址发生变化,重新记录当前的路径
initEvent() {
window.addEventListener("popstate", () => {
this.data.current = window.location.pathname;
});
}
}
推荐阅读
- 做一件事情的基本原理是什么()
- 关于QueryWrapper|关于QueryWrapper,实现MybatisPlus多表关联查询方式
- MybatisPlus使用queryWrapper如何实现复杂查询
- python学习之|python学习之 实现QQ自动发送消息
- 孩子不是实现父母欲望的工具——林哈夫
- opencv|opencv C++模板匹配的简单实现
- Node.js中readline模块实现终端输入
- java中如何实现重建二叉树
- 【读书笔记】贝叶斯原理
- 人脸识别|【人脸识别系列】| 实现自动化妆