latest一直在翻看Vue和React路由的相关知识,最后发现这些路由框架的模块功能的实现都是基于浏览器的本机路由API。本着追根溯源的初衷,想整体梳理一下浏览器原生的路由API,以便更顺利的理解Vue-Router和React-Router的相关实现和原理。后台浏览器的主要功能是根据输入的URL在窗口中加载相应的文档。同时,浏览器会在一个标签窗口中记录所有加载的文档,并提供“前进”、“后退”和“刷新”功能,用户可以在这些记录的文档之间切换,重新加载当前页面获取最新浏览信息。这些功能的实现首先是在服务器端实现的,因为当时的引用没有前后端分离,页面内容也是动态生成的,所以这些页面的跳转、切换、刷新都是全部在服务器端实现。后来出现了SPA(SinglePageApplication)。页面通过JavaScript动态生成加载到页面中,无需刷新即可加载页面的最新状态信息。这时候如果要提供以上功能需要自己处理(因为此时的页面都在同一个大框架页面中,根本没有页面跳转切换),所以Router实现对应各种框架已经诞生。在浏览器中实现前端路由主要有两种方式:一种是我们常用的hash,一种是HTML5提供的history。事实上,Node.js服务器端还有另一种使用堆栈的方法。在这里,我们将重点关注浏览器提供的哈希和历史记录。stack是如何实现的,上一次讲x-Router源码的时候会详细讲到。hash在浏览器的URL地址栏,我们总会找到这样一个地址:react.docschina.org/docs/react-...React官网关于lazy的地址)。想必大家已经发现了:在这串url的末尾有一串#开头的标志,那么它到底起到了什么样的作用呢?绝对不会无缘无故出现的。借助哈希功能,您可以直接在浏览器中打开此链接地址。您是否发现该页面会自动滚动到(位于页面顶部)标题为React.lazy的文档的一部分。再往上翻页面,肯定会发现上面还有一些文档内容。此时,你将地址栏的地址修改为react.docschina.org/docs/react-...React.Suspense部分。在早期,散列被用作URL的一部分来定位文档中的文档片段。在上面的示例中,我们通过在URL末尾添加#reactlazy和#reactsuspense来定位文档中标题为React.lazy和React.Suspense的部分。那么他们到底是怎么做到的呢?通过查看元素,我们发现在React.lazy和React.Suspense对应的title部分分别有一个h3标签,标签的id属性对应我们在URL地址栏输入的hash值(只是漏了标志)。可能有同学对hash定位文档片段有疑惑:hash为什么要通过元素上的id属性来定位文档呢?正如我们前面提到的,URL的哈希部分用于在文档中定位文档片段。想一想:需要定位的文档片段必须是唯一的,否则定位肯定不准确,那这个定位文档就有点鸡肋了,文档中唯一标识的属性是id,如果是我,我也的文档将通过哈希匹配元素的id来定位。现在来验证一下我们的猜想:1.首先在新的tab窗口打开react.docschina.org/docs/react-...页面,然后在audit元素下找到上图所示的DOM元素,修改其中的h3标签它的id属性值为reactlazy1,然后在URL地址栏中加上#reactlazyhash值并回车。此时页面没有定位到标题为React.lazy的文档片段,最后将URL地址栏中的#reactlazy哈希值改为输入#reactlazy1哈希值并回车。此时页面并没有定位到名为React.lazy的文档片段。这一系列的表现说明hash位置还是和元素的id属性值有关;2.还是在新的tab窗口打开react.docschina.org/docs/react-...页面,然后手动滚动页面到标题为React.lazy的文档片段,鼠标放在上面会出现一个锚点图标标题。点击图标发现页面定位到标题为React.lazy的文档片段,URL地址栏变为react.docschina.org/docs/react-...#reactlazy哈希值。这时候回过头来看我们之前给的截图,发现id属性值为reactlazy的h3标签有一个href属性值为#reactlazy的a标签。其实我们在页面上看到的锚点图标就是a标签。展示。当我们点击锚点图标时,我们点击a链接,然后定位到id属性值为reactlazy的h3标签的url,很好的说明hash位置还是和元素的id属性值有关;3.MDN官方定义如下:MDN官方文档中有明确的定义,但是我们还是通过两个方面来证明我们的推论。乍一看,好像说了很多没用的话。其实,这样的反复推敲,更有利于我们深入理解相关知识点,为什么是这样,不是那样!hashroutehash不仅可以通过设置文档中元素的ID来定位文档片段,还可以设置为任意字符串来表示路由。在Vue、React等现代前端框架中,为了实现功能齐全的SPA应用,都配备了相应的路由系统。这些路由系统都提供哈希路由模式。在哈希模式下,哈希将支持任意字符串来表示对应的URL。这些路由系统对于hash模式的实现基本相同:在设置location的值之后。更新自己的状态。支持HTML5的浏览器一旦发现fragmentidentifier发生变化,就会触发Window对象上的hashchange事件,进而触发对象的函数处理逻辑——解析location.hash的值,然后使用该值包含state重新呈现应用程序的信息。这里只是一个基本思路,路由系统的具体实现会在后面讲解!hashevent//监听window下的hashchange事件window.onhashchange=function(){//触发事件时输出当前hash值console.log(window.location.hash)}在不支持HTML5的浏览器中,我们可以通过100ms的轮询来模拟监听url变化:(function(window){//如果浏览器不支持原生实现的事件,则开始模拟,否则退出。如果(window.document.body中的“onhashchange”)返回;varlocation=window.location,oldUrl=location.href,oldHash=location.hash;//每100ms检测一次hash是否变化setInterval(function(){varnewUrl=location.href,newHash=location.hash;//hash变化,全局注册onhashchange方法(这个名字要和模拟事件名称);if(newHash!==oldHash&&typeofwindow.onhashchange==="function"){//执行方法window.onhashchange({type:"hashchange",oldURL:oldUrl,newURL:newUrl});oldUrl=newUrl;oldHash=newHash;}},100);})(window)??注意:设置location.hash属性会更新地址栏中显示的URL,并在浏览器的历史记录中添加一条记录。History为了规范浏览器历史管理的管理,HTML5定义了一个相对复杂的API——history。Historyapi1和history添加了两个新的API,history.pushState()和history.replaceState()。两个API都接受相同的参数:它们的区别在于:history.pushState()方法是将新状态添加到浏览器的历史记录中,也就是说,通过单击“返回”按钮,返回到上一个页面;history.replaceState()是将当前的历史状态替换为新的状态,也就是说没有更多的历史记录,“后退”按钮不能操作,页面不能“后退”。??注意:执行这两个API时,浏览器的URL地址栏会发生变化,但不会刷新页面内容!StateObject(state
