前端路由的两种模式

本文详细介绍了前端路由的两种模式:hash模式和history模式。在hash模式中,利用URL hash的变化实现页面内容的无刷新更新,而history模式通过window.history对象的pushState和replaceState方法改变URL,不触发HTTP请求。两者在手动刷新时的行为有所不同,history模式可能需要服务端配合处理404情况。文章最后提到了JS面试题的分享。

一、  hash模式

1、认识window.location

表示其链接到的对象的位置(URL)。在控制台打印window.location,可以看到有以下的属性和方法

其中window.location.hash会存有一个哈希值,这个hash是指URL中:

#之后的路径地址(包含#)

2、hash在页面中有什么作用

● 锚点定位

<script type="text/javascript">
function showNode (oNode) {var nLeft = 0, nTop = 0;for (var oItNode = oNode; oItNode; nLeft += oItNode.offsetLeft, nTop += oItNode.offsetTop, oItNode = oItNode.offsetParent);window.scrollTo(nLeft, nTop); 
}

function showBookmark (sBookmark, bUseHash) {if (arguments.length === 1 || bUseHash) {window.location.hash = sBookmark;return;}var oBookmark = document.querySelector(sBookmark);if (oBookmark) { showNode(oBookmark); }
}
</script> 
<p id="myBookmark1"><span class="intLink" onclick="showBookmark('#myBookmark2');">Go to bookmark #2</span>
</p>
...
<p id="myBookmark2"><span class="intLink" onclick="showBookmark('#myBookmark1');">Go to bookmark #1</span>
</p> 

通过以上代码,可以实现在同一个文档下,可以通过点击到达对应的书签处,那我们怎么知道当前处在哪个书签呢?可以将该书签作为一个URL的hash。

同样的场景,其实通过a标签也能实现

<nav><ul><li><a href="#md01"> 跳转到锚点1</a></li><li><a href="#md02"> 跳转到锚点2</a></li></ul>
</nav>
<main><ul><li id="md01">锚点一</li><li id="md02">锚点二</li></ul>
</main> 

你会发现:在同一个文档下,指定到某一块元素,URL的hash是会变化的,但是不会对页面重新发起请求

3、hashchange()

当 URL 的片段标识符更改时,将触发hashchange事件 (跟在#符号后面的 URL 部分,包括#符号),因此可以监听hashchange去做你想做的事情

function locationHashChanged() {console.log('The hash has changed!')
}
window.onhashchange = locationHashChanged; 

4、hash的应用

基于以上的说明,可以利用URL hash的变化不会重新发起http请求去实现页面内容的变化

<a href="#/a">A页面</a>
<a href="#/b">B页面</a>
<div id="app"></div>
<script> function render() {app.innerHTML = window.location.hash}window.addEventListener('hashchange', render) </script> 

二、  history模式

1、  认识window.history

获取History对象的引用,提供了操作浏览器会话历史(浏览器地址栏中访问的页面,以及当前页面中通过框架加载的页面)的接口。

可以看到该对象继承原型上的有关对会话历史操作的几个接口,下面来介绍几个重要的接口

2、  方法
2.1 前进、后退
back() 

此异步方法转到浏览器会话历史的上一页,与用户单击浏览器的返回按钮,等价于 history.go(-1)

forward() 

此异步方法转到浏览器会话历史的下一页,与用户单击浏览器的前进按钮,等价于 history.go(1)

go() 

通过当前页面的相对位置从浏览器历史记录(会话记录)异步加载页面。比如:参数为 -1 的时候为上一页,参数为 1 的时候为下一页。

2.2 pushState()

会在当前的 document 中创建和激活一个新的历史记录

history.pushState(state, title[, url]) 
state是一个 JavaScript 对象,它与pushState()创建的新历史记录条目相关联,即传递给新URL的参数
title大多数浏览器忽略,可传递空字符串应该可以防止将来对方法的更改
url非必传,如果是有传,则相对于当前 URL 进行解析。新网址必须与当前网址同源,否则会引发异常

参考例子:

1.新建test目录下新建test.html

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title></title></head><body><a href="javascript:toA();">A页面</a><a href="javascript:toB();">B页面</a><a href="javascript:toC();">返回</a><script>Cfunction toA() {history.pushState({a: 111}, '', '/a')}Cfunction toB() {history.pushState({b: 222}, '', '/b')}function toC() {history.back()} </script></body>
</html> 

2.test目录下终端执行

npm i -g light-server 

3.test目录下终端执行

light-server -s .--port 3000 

4.打开test.html

分别点击A页面,B页面,可以看到URL会发生以下变化

http://localhost:3000/test.htmlhttp://localhost:3000/ahttp://localhost:3000/b

每次变化后观察控制台你会发现当前页面并不会重新发起http请求

注意:

从某种程度来说,调用 pushState() 和 window.location = "#foo"基本上一样,他们都会在当前的 document 中创建和激活一个新的历史记录,但是 pushState() 有以下优势:

1.  新的 URL 可以是任何和当前 URL 同源的 URL。但是设置 window.location 只会在你只设置锚的时候才会使当前的 URL。

2.  非强制修改 URL。相反,设置 window.location = “#foo”; 仅仅会在锚的值不是 #foo 情况下创建一条新的历史记录。

3.  可以在新的历史记录中关联任何数据。window.location = "#foo"形式的操作,你只可以将所需数据写入锚的字符串中。

4.  pushState()不会造成hashchange事件调用,即使新的URL和旧的URL只是锚点的不同

2.3 replaceState()

把当前历史记录实体替换成新的记录(url有传的情况,否则保留当前记录),可以用于更新当前的 state 对象或者当前历史实体的 URL 来响应用户的的动作

history.replaceState(stateObj, title[, url]); 

参数和pushState()一致

替换之后历史记录里面则不存在被替换掉的记录了,也就是对历史记录做前进,后退操作则不会定位到被替换掉的记录

2.4 popState()

前进后退操作会触发popState事件,而replaceState(), pushState()则不会触发。

如果当前处于激活状态的历史记录条目是由 history.pushState() 方法创建的或者是由 history.replaceState() 方法修改的,则 popstate 事件的 state 属性包含了这个历史记录条目的 state 对象的一个拷贝。

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title></title></head><body> <a href="javascript:toA();">A页面</a><a href="javascript:toB();">B页面</a><a href="javascript:toC();">返回</a><div id="app"></div> <script> function render(str) {app.innerHTML = window.location.pathname + str}function toA() {history.pushState({a: 111}, null, '/a')render('AAA')}function toB() {history.pushState({b: 222}, null, '/b')render('BBB')}function toC() {history.back()}window.onpopstate = function(event) {console.log(event)render('CCC')} </script></body>
</html> 

三、  hash模式和history模式的区别

1、  hash(#)的改变虽然让URL看起来不同,但是在手动刷新页面的时候,HTTP请求会自动忽略hash,请求的还是同一个URL。

2、  history模式不带有#符号,但是如果通过pushState或者replaceState改变了URL,在手动刷新的时候,HTTP请求会以当前实际的URL发送请求,这就可能出现资源路径请求404的情况,因此需要服务端做重定向。

3、  不管是hash模式还是history模式,都可以做到修改URL不重新发起HTTP页面请求

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值