Javascript 前端路由的简单实现(hash模式和history模式)
Javascript 前端路由的简单实现(hash模式和history模式)
路由是根据不同的url地址来显示不同的页面或内容的功能。 之前的路由主要是后端路由,对应不同的路由,服务端会返回相应的数据(html, json等等),然后浏览器重新解析和渲染。后端路由有一个很大的问题是路由切换的时候会频繁刷新页面,对用户体验来说并不友好。在这个背景之下,前端路由出现了,它可以实现路由切换同时不刷新页面。
在常用的前端框架(Vue, React 等)中,通常会有 hash 路由 和 history 路由两种路由方式。
hash 路由:监听 url 中 hash 的变化,渲染不同的内容,这种路由不向服务器发送请求,不需要服务端的支持;
history 路由:监听 url 中的路径(path)变化,渲染不同的内容,这种路由不向服务器发送请求,需要客户端和服务端共同的支持;
注意,这里的需要服务端的支持并不是指会向服务器发送请求,而是因为框架和history模式的特性,需要在服务端进行一些配置。如果服务端没有配置新更新的 url ,一刷新浏览器就会报错,因为刷新浏览器会真实地向服务器发送一个 http 的请求。因此若要使用 history 路由,需要服务端的支持。具体可以参考这一篇文章 vue-router history模式 为什么需要服务端配置以及如何配置
一、hash模式
hash模式主要是监听 url 中 hash 的变化,这里就必须提到一个关键的对象 window.location。
改变hash不会触发页面跳转,因为hash链接是当前页面中的某个片段,所以如果hash有变化,那么页面将会滚动到hash所连接的位置。但是页面中如果不存在hash对应的片段,则没有任何效果。
属性 | 含义 |
---|---|
location.href | 完整的url |
location.protocol | 当前URL的协议,包括 : ; 比如 https: |
location.host | 主机名和端口号 |
location.hostname | 主机名 |
location.port | 端口号 |
location.pathname | url的路径部分,从 / 开始; |
location.search | 查询参数,从 ? 开始 |
location.hash | hash值,从 # 开始的 |
可以发现 href = protocol + host(hostname+port) + pathname + search + hash
hash模式主要用到的是location.hash
hash路由的特点:
url中hash值的改变,不会重新加载页面。
通过hashchange事件可以监听到hash值的变化。
hash值的改变会在浏览器的访问历史中增加一条记录。
注意,
事件
hashchange
只会在 hash 发生变化时才能触发,而第一次加载页面时并不会触发这个事件,因此我们还需要监听load
事件。这两个事件的 event对象 是不一样的:hashchange 事件中的 event 对象有 oldURL 和 newURL 两个属性,可以从中提取出 preHash 和 currentHash 。但是 load 事件中的 event 没有这两个属性,不过我们可以通过 location.hash 来获取到当前的 hash 路由。
1. hash模式的简单实现
//hash路由 class HashRoute { constructor() { //存储对象 this.routes = {}; //当前hash this.currentHash = '' //绑定this.避免监听时this指向改变 this.freshRoute = this.freshRoute.bind(this); //监听 // 页面加载事件 window.addEventListener('load', this.freshRoute, false); // hashchange事件 window.addEventListener('hashmessage', this.freshRoute, false); } // 存储 storeRoute(path, callback) { this.routes[path] = callback || function () { }; } // 触发 freshRoute() { this.currentHash = getHash(); let callback = this.routes[this.currentHash] if (typeof callback === "function") callback() } // 获取当前hash值 getHash() { return location.hash.slice(1) || '/'; } } 复制代码
二、history模式
history模式主要是监听 url 中 path 的变化,这里就必须提到两个关键的对象 window.location和window.history。
window.history对象的常用方法
方法 | 作用 |
---|---|
pushState(obj, title, url) | 前进到指定的 url,history栈会新增一条记录,不刷新页面 |
replaceState(obj, title, url) | 用 url 替换当前的路由,history栈不会新增记录,不刷新页面 |
forward() | 前进到下一个路由,如果存在的话 |
back() | 后退到上一个路由 |
go(number) | 进入到任意一个路由,正数为前进,负数为后退 |
history路由的特点:
url中path值的改变,不会重新加载页面。
通过popstate事件可以监听到path值的变化。
注意,
和hash路由一样,
popstate
事件只会在 history 发生变化时才能触发,而第一次加载页面时并不会触发这个事件,因此我们还需要监听load
事件。pushState
和replaceState
被调用时,不会触发触发 popstate 事件的,但是我们可以使用window.dispatchEvent
来添加事件。
1. history模式的简单实现
//history路由 class HistoryRoutes { constructor() { //存储对象 this.routes = {}; //当前path this.currentPath = ''; //绑定this.避免监听时this指向改变 this.freshRoute = this.freshRoute.bind(this); //监听事件 window.addEventListener('load', this.freshRoute, false); window.addEventListener('popstate', this.freshRoute, false); window.addEventListener('pushState', this.freshRoute, false); window.addEventListener('replaceState', this.freshRoute, false); } // 存储 storeRoute(path, callback) { this.routes[path] = callback || function () { }; } // 触发 freshRoute() { this.currentPath = this.getState(); this.routes[this.currentPath] && this.routes[this.currentPath](); } // 初始化 init(path) { history.replaceState(null, null, path); this.routes[path] && this.routes[path](); } // 跳转 go(path) { history.pushState(null, null, path); this.routes[path] && this.routes[path](); } // 获取路由路径 getState() { const path = window.location.pathname; return path ? path : '/'; } }
作者:Happyileaf
链接:https://juejin.cn/post/7031561396554825741