手写简易VueRouter
前言
路由是用来跟后端服务器进行交互的一种方式,通过不同的路径来请求不同的资源,请求不同的页面是路由的其中一项功能。VueRouter则是Vue的路由管理器
VueRouter本质
根据"不同的hash值"或者"不同的路径地址", 将不同的内容渲染到router-view
中 所以实现VueRouter
的核心关键点就在于如何监听'hash'或'路径'的变化, 再将不同的内容写到router-view
中
popstate监听历史记录点
vue-router 的 history 模式是使用浏览器的 history state
来实现的,history state
是通过 History 对象来操作的。 popstate
事件是通过 window.addEventListener('popstate')
进行注册的。但触发条件需要满足下面两点:
- 点击浏览器的【前进】【后退】按钮,或者调用
history
对象的back
、forward
、go
方法 - 之前调用过
history
对象的replaceState
或pushState
方法
<a onclick="go('/home')">首页</a>
<a onclick="go('/about')">关于</a>
<div id="html"></div>
function go(path) {// console.log(path);history.pushState(null, null, path);document.querySelector('#html').innerHTML = path;
}
window.addEventListener('popstate', ()=>{console.log('点击了前进或者后退', location.pathname);document.querySelector('#html').innerHTML = location.pathname;
})
hashchange 事件
- 当URL的片段标识符更改时,将触发
hashchange
事件(跟在#符号后面的URL部分,包括#符号) hashchange
事件触发时,事件对象会有hash
改变前的URL(oldURL)
和hash
改变后的URL(newURL)两个属性
window.addEventListener('hashchange', ()=>{// console.log('当前的hash值发生了变化');let currentHash = location.hash.slice(1);document.querySelector('#html').innerHTML = currentHash;
})
VueRouter结构
src-> router-> index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import About from '../views/About.vue'Vue.use(VueRouter)const routes = [{path: '/home',name: 'Home',component: Home},{path: '/about',name: 'About',component: About}
]const router = new VueRouter({mode: 'history', base: process.env.BASE_URL,routes
})export default router
提取路由信息
创建一个新的js文件(myVue-Router.js),搭建基本的路由信息框架
class VueRouter {constructor(options){this.mode = options.mode || 'hash';this.routes = options.routes || [];this.routesMap = this.createRoutesMap();}createRoutesMap(){return this.routes.reduce((map, route)=>{map[route.path] = route.component;return map;}, {})}
}
VueRouter.install = (Vue, options)=>{}
export default VueRouter;
初始化路由信息
class VueRouteInfo {constructor(){this.currentPath = null;}
}
class VueRouter {constructor(options){this.mode = options.mode || 'hash';this.routes = options.routes || [];// 提取路由信息this.routesMap = this.createRoutesMap();// 记录当前路由this.routeInfo = new VueRouteInfo();// 初始化默认的路由信息this.initDefault();}initDefault(){if(this.mode === 'hash'){// 1.判断打开的界面有没有hash, 如果没有就跳转到#/if(!location.hash){location.hash = '/';}// 2.加载完成之后和hash发生变化之后都需要保存当前的地址window.addEventListener('load', ()=>{this.routeInfo.currentPath = location.hash.slice(1);});window.addEventListener('hashchange', ()=>{this.routeInfo.currentPath = location.hash.slice(1);console.log(this.routeInfo);});}else{// 1.判断打开的界面有没有路径, 如果没有就跳转到/if(!location.pathname){location.pathname = '/';}// 2.加载完成之后和history发生变化之后都需要保存当前的地址window.addEventListener('load', ()=>{this.routeInfo.currentPath = location.pathname;});window.addEventListener('popstate', ()=>{this.routeInfo.currentPath = location.pathname;console.log(this.routeInfo);});}}createRoutesMap(){return this.routes.reduce((map, route)=>{map[route.path] = route.component;// { /home: Home }return map;}, {})}
}
VueRouter.install = (Vue, options)=>{}
export default VueRouter;
注入全局属性
VueRouter.install = (vm, options)=>{vm.mixin({beforeCreate(){if(this.$options && this.$options.router){this.$router = this.$options.router;this.$route = this.$router.routeInfo;// 实时监听路由变化vm.util.defineReactive(this, 'xxx', this.$router);}else{this.$router = this.$parent.$router;this.$route = this.$router.routeInfo;}}});
}
自定义RouterLink
vm.component('router-link', {props: {to: String},render(){// console.log(this._self.$router.mode);let path = this.to;if(this._self.$router.mode === 'hash'){path = '#' + path;}return <a href={path}>{this.$slots.default}</a>}
});
自定义RouterView
vm.component('router-view', {render(h){let routesMap = this._self.$router.routesMap;let currentPath = this._self.$route.currentPath;let currentComponent = routesMap[currentPath];return h(currentComponent);}
});
完整示例
App.vue
<template><div id="app"><div id="nav"><router-link to="/home">Home</router-link> |<router-link to="/about">About</router-link></div><router-view></router-view></div>
</template>
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'Vue.config.productionTip = falsenew Vue({router,render: h => h(App)
}).$mount('#app')
src-> router-> index.js 看上面的VueRouter结构
src-> router-> myVue-Router.js
class VueRouteInfo {constructor(){this.currentPath = null;}
}
class VueRouter{constructor(options){this.mode = options.mode || 'hash';this.routes = options.routes || [];// 1、提取路由信息this.routesMap = this.createRoutesMap();this.routeInfo = new VueRouteInfo();// 2、初始化默认的路由信息this.initDefault();}createRoutesMap(){return this.routes.reduce((map, route) =>{// 组件作为key返回map[route.path] = route.component;return map;},{})}initDefault(){if (this.mode === 'hash'){// 1) 判断打开的界面有没有hash, 如果没有就跳转到#/if (!location.hash){location.hash = '/'}// 2) 加载完成之后和hash发生变化之后都需要保存当前的地址window.addEventListener('load', ()=>{this.routeInfo.currentPath = location.hash.slice(1);});window.addEventListener('hashchange', ()=>{this.routeInfo.currentPath = location.hash.slice(1)})} else {// 1) 判断打开的界面有没有路径, 如果没有就跳转到/if (!location.pathname){location.pathname = '/'}// 2)加载完成之后和history发生变化之后都需要保存当前的地址window.addEventListener('load', ()=>{this.routeInfo.currentPath = location.pathname});window.addEventListener('popstate', ()=>{this.routeInfo.currentPath = location.pathname;});}}
}
VueRouter.install = (vm, options) =>{// 3、全局注入属性vm.mixin({beforeCreate() {if (this.$options && this.$options.router){this.$router = this.$options.router;this.$route = this.$router.routeInfo;// 实时监听路由变化vm.util.defineReactive(this, 'xxx', this.$router);} else {this.$router = this.$parent.$router;this.$route = this.$router.routeInfo;}}});// 4、自定义路由组件vm.component('router-link', {props: {to: String},render() {let path = this.to;if(this._self.$router.mode === 'hash'){path = '#' + path;}return<a href={path}>{this.$slots.default}</a>}})vm.component('router-view', {render(h) {let routerMap = this._self.$router.routesMap;let currentPath = this._self.$route.currentPath;let currentComponent = routerMap[currentPath];return h(currentComponent)}})
};
export default VueRouter
手写简易VueRouter相关推荐
- 手写简易版链表及原理分析
好多人都觉得为什么要自己写这样的数据结构,变成里面不是有吗?为什么要去写,有这个疑问,其实这个疑问这我的脑海中也存在了很长一段时间,本人是学习java编程的,直接看java的集合框架不行吗?这个时候如 ...
- 解鞍卸甲——手写简易版Spring框架(终):使用三级缓存解决循环依赖问题
什么是三级缓存 按照目前我们实现的 Spring 框架,是可以满足一个基本需求的,但如果你配置了A.B两个Bean对象互相依赖,那么立马会抛出 java.lang.StackOverflowError ...
- React,手写简易redux(二)- By Viga
React,手写简易redux(二) 本章节会完成一个简易的redux实现 该系列内容会逐步实现简易的redux 使用技术栈:vite+react 该系列感谢@方应杭 的react教学视频 目录 实现 ...
- spring源码分析01-(前期准备)spring核心原理解析和手写简易spring
1.本文主要介绍内容 本文会把Spring中核心知识点大概解释下.可以对Spring的底层有一个整体的大致了解.主要内容包括: 手写简易spring框架,帮助更好理解spring. 代码点击链接自取 ...
- 手写简易WEB服务器
手写简易WEB服务器 今天我们来写一个类似于Tomcat的简易服务器.可供大家深入理解一下tomcat的工作原理,本文仅供新手参考,请各位大神指正! 首先我们要准备的知识是: Socket编程 HTM ...
- 5 拦截器拦截请求路由_手写简易版axios拦截器,实现微信小程序wx.request的封装与拦截...
前言: axios是一个功能强大的网络请求库,其中拦截器又是axios的精髓.在小程序的开发或者需要手动实现ajax的时候,没有实现对请求的拦截,开发的时候非常不方便,因此手写一个简易版的axios拦 ...
- 手写简易版 React 来彻底搞懂 fiber 架构
React 16 之前和之后最大的区别就是 16 引入了 fiber,又基于 fiber 实现了 hooks.整天都提 fiber,那 fiber 到底是啥?它和 vdom 是什么关系? 与其看各种解 ...
- 手写简易Spring
项目描述 项目描述: 手写Spring启动以及扫描流程 手下getBean()流程 手写Bean生命周期流程 手写依赖注入流程 手写BeanPOSTProcessor机制 手写AOP机制 0. Spr ...
- 手写简易版Vue源码之数据响应化的实现
当前,Vue和React已成为两大炙手可热的前端框架,这两个框架都算是业内一些最佳实践的集合体.其中,Vue最大的亮点和特色就是数据响应化,而React的特点则是单向数据流与jsx. 笔者近期正在研究 ...
最新文章
- 【HDOJ】4343 Interval query
- [Leetcode] Flatten Binary Tree to Linked List 整平二叉树
- 图论--一般带花树匹配
- python3-matplotlib绘制散点图、绘制条形图
- 【操作系统】—内存的基本知识
- J.U.C - AQS
- Point to Raster 工作原理
- Windows Server 2012 R2磁盘分区
- TCP segment of a reassembled PDU,就这么简单!
- 测试自动化成本及投资回报率
- linux格式化硬盘 中断,linux格式化硬盘【调解方案】
- java中的坦克大战游戏设计报告论文_基于Android平台坦克大战游戏的设计与实现...
- 面试题,你为什么想做产品经理?
- C语言——计算阶层求和
- 线程的启动暂停和终止
- js文件 本地 上传服务器地址,js 本地文件同步服务器地址
- pandas 数据怎样实现行间计算
- windows服务器署站点,Windows Server配置学习心得-web服务器的搭建和部署,配置一个BLOG站点...
- 字节跳动技术岗官方解析 · 客户端篇:业务、中台、infra,这里的客户端究竟是怎样的?...
- 精灵图(sprite)CSS动画实现
热门文章
- 浅谈单工,半双工和全双工有何区别和联系?
- BMZCTF baby_dsa
- gta5nat严格怎么办_如何解决在游玩 GTA 在线模式时出现的 NAT 类型为“严格”(Strict)的错误...
- openwrt上用stun实现NAT类型检测
- 结合数学分析、复变函数重新看待指数函数e^{x}
- A.M. Best确认中国再保险(集团)股份有限公司及其子公司信用评级
- pull request
- Office 2007 Proofing 拼写检查失效解决方法
- matlab中gad,10大经典算法matlab代码以及代码详解【数学建模、信号处理】
- 幕维动画为你解答沉管三维动画有什么用