hash模式
什么是 hash 值?hash 值是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)。可以通过 window.location.hash 获取。举个例子: www.baidu.com/#home。 那这个 hash 值就是 #home 了。
hash值变化浏览器不会重新发起请求,但是会触发window.hashChange事件,假如我们在hashChange事件中获取当前的hash值,并根据hash值来修改页面内容,则达到了前端路由的目的。
<body>
<a href="#/home">home</a>
<a href="#/about">about</a>
<div id="routeView" style="width: 100;height: 100;">
</div>
<script>
// 页面加载完不会触发DOMContentLoaded,这里主动触发一次 hashchange 事件
window.addEventListener('DOMContentLoaded', onLoad)
// 监听路由变化
window.addEventListener('hashchange', onHashChange)
// 路由视图
var routerView = null
function onLoad () {
routerView = document.querySelector('#routeView')
onHashChange()
}
// 路由变化时,根据路由渲染对应 UI
function onHashChange (e) {
switch (location.hash) {
case '#/home':
routerView.innerHTML = 'Home'
return
case '#/about':
routerView.innerHTML = 'About'
return
default:
return
}
}
</script>
</body>
history模式
history模式基于window.history对象的方法
在HTML4中,已经支持window.history对象来控制页面历史记录跳转,常用的方法包括:
-
history.forward(); //在历史记录中前进一步
-
history.back(); //在历史记录中后退一步
-
history.go(n): //在历史记录中跳转n步骤,n=0为刷新本页,n=-1为后退一页。
在HTML5中,window.history对象得到了扩展,新增的API包括:
-
history.pushState(data[,title][,url]);//向历史记录中追加一条记录
-
history.replaceState(data[,title][,url]);//替换当前页在历史记录中的信息。
-
history.state;//是一个属性,可以得到当前页的state信息。
-
window.onpopstate;//是一个事件,在点击浏览器后退按钮或js调用forward()、back()、go()时触发。监听函数中可传入一个event对象,event.state即为通过pushState()或replaceState()方法传入的data参数
我们打印下history对象就可以看见这些属性和方法
下面展示一下用法
//返回一个整数(Integer),该整数表示会话历史中元素的数目,
//包括当前加载的页。例如,在一个新的选项卡加载的一个页面中,这个属性返回 1
console.log(history.length)
// 允许 Web 应用程序在历史导航上显式地设置默认滚动恢复行为。
//此属性可以是自动的(auto)或者手动的(manual)
console.log(history.scrollRestoration)
// 此异步方法转到浏览器会话历史的上一页,与用户单击浏览器的 Back 按钮的行为相同。
//等价于 history.go(-1)。
history.back()
// 此异步方法转到浏览器会话历史的下一页,与用户单击浏览器的 Forward 按钮的行为相同。
//等价history.go(1)
history.forward()
// 通过当前页面的相对位置从浏览器历史记录(会话记录)异步加载页面。
//比如:参数为 -1 的时候为上一页,参数为 1 的时候为下一页。
// 当你指定了一个越界值(例如:当会话历史记录中没有之前访问的页面时,则传参的值为 -1,
//那么这个方法没有任何效果也不会报错。调用没有参数的 go() 方法或者参数值为 0 时,
//重新载入当前页面。
history.go()
history.push
history.replaceState(data[,title][,url]),相当于添加了一条页面记录,第一个参数是state(状态对象),第二个参数是title(可忽略),第三个参数是url
注意
history.pushstate方法修改url不能跨域。因为该项目是直接通过浏览器打开index.html文件就可以查看。修改了原有的地址会进行报错。如果启动本地服务器不会存在这个问题。报错信息如下:
Failed to execute 'pushState' on 'History': A history state object with URL...
下面我在vue项目演示一下
当前我只设置了两个有效的路由,所以只有/haveView和/homeView会显示页面
在homeView中加入下面代码
此时再进入homeview页面,就会添加一条路由记录,显示地址为his.htlm ,但是实际却是homeview页面就说明调用 pushState()
后浏览器并不会立即加载这个 URL,但可能会在稍后某些情况下加载这个 URL,比如在用户重新打开浏览器时。
history.replaceState()
history.replaceState()
的使用与 history.pushState()
非常相似,区别在于 replaceState()
是修改了当前的历史记录项而不是新建一个。注意这并不会阻止其在全局浏览器历史记录中创建一个新的历史记录项。
区别
1、 history和hash都是利用浏览器的两种特性实现前端路由,history是利用浏览历史记录栈的API实现,hash是监听location对象hash值变化事件来实现
2、
HashRouter的原理:通过window.onhashchange方法获取新URL中hash值,再做进一步处理 HistoryRouter的原理:通过history.pushState 使用它做页面跳转不会触发页面刷新,使用window.onpopstate 监听浏览器的前进和后退,再做其他处理
3、 history的url没有’#'号,hash反之
4、 相同的url,history会触发添加到浏览器历史记录栈中,hash不会触发
5、发送请求时:
hash: 仅 hash 符号之前的内容会被包含在请求中,**因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。**(这就是前端人员比较喜欢的,不用出404)
history: 前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.abc.com/book/id。 如果后端缺少对 /book/id 的路由处理,将返回 404 错误。