深入理解React Router:从原理到实践
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.3.2 history导航

1.history.push

history.push类似于1.2.1节中的history.pushState,会添加新的历史栈记录。其调用语法为:

其接收字符形式的路径,也接收location地址描述对象。

hashHistory使用浏览器地址的hash部分作为路由存储,每次hashHistory.push调用仅改变浏览器地址的hash值,这在某些不支持HTML5特性的旧式浏览器中可被使用。hashHistory.push的底层history源码为:

调用window.location.hash进行一次hash改变,从而实现改变浏览器地址hash并入栈的操作。

注意,对于location,history.push调用是按照整个浏览器协议进行的,如可调用history.push('/foo/baz#121')。这会在浏览器中产生两个#号,第一个#号后为hashHistory所标识的地址,第二个#号后为hashHistory中location的hash值,如:

如同browserHistory一样,hashHistory也可调用hashHistory.block阻止导航;导航时也可以传入相对路径参数。

注意,如果hashHistory.push设置了state参数,则第4版本的history库会给出警告:

由于考虑兼容性问题,第4版本的history库没有使用pushState的底层接口。因此,对应的历史栈状态也无法存储,history进行了忽略并提示开发者。

对于hashHistory.push的参数,也可以为location对象,其类型描述如下:

若hashHistory.push方法的第一个参数为对象,则可分别设置hashHistory的pathname、search和hash等:

如果希望hashHistory也能传递一个state对象,则可在location对象中设置state:

第4版本的history库不建议在hashHistory中使用state,虽然可通过location对象传递state,但是其作为页面级别的state,不具备持久化state的能力。这时,仅能从hashHistory.location.state中读取到对象{some:'state'},而不能从window.history.state中读取到。例如在浏览器中执行一次后退再前进的操作,由于window.history.state没有存储状态,这时读取hashHistory.location.state,读取到的值将为空。而browserHistory可以再次读取到state值,所以需要注意,hashHistory.location.state在导航过程中并不能如browserHistory一样其state值能得到再现。由于pushState等HTML5接口已经被广泛使用,在history库未来的第5版本中将使用pushState来模拟hashHistory,因此持久化的state设置会得到支持。此时,hashHistory设置的state也可从window.history.state中读取到。相关的持久化能力可查看1.2.1节。

2.history.replace

使用history.replace可替换历史栈中的栈记录。history.replace的使用方式与history.push类似,其签名如下:

调用history.replace同样会修改浏览器地址,但其如browserHistory的replace方法一样,仅替换某个历史记录:

在history库源码中,hashHistory使用window.location.replace接口,以达到仅替换历史栈记录而不添加历史栈记录的目的:

注意,与browserHistory不同的是,hashHistory在创建时没有keyLength选项,这对应到hashHistory.push、hashHistory.repalce方法不产生key值,即hashHistory.location.key为undefined:

这里需要提一下base元素基准路径处理问题,如果HTML文档流中存在base元素,且base元素的href属性不为空,则在history v4.10.0中,替换hash的方法如下:

history.replace调用的replaceHashPath会在window.location.href没有#号时,得到window.location.href.slice(0,0)的结果。由于window.location.href.slice(0,0)返回空字符串,因此实际会调用:

但是对于有base元素的HTML文档来说:

window.location.replace仅传入hash字符串的调用会将window.location.pathname改成base的值,原pathname将丢失,如:

假若当前路径为https://example.com/foo/baz,且有href属性值为/base/的base元素存在,在调用window.location.replace("#path")后,原路径中/foo/baz将会丢失。若要避免丢失,则需要将/foo/baz也一起传入,如window.location.replace("/foo/baz/#path")。

在history v4.10.1中,replaceHashPath方法改为了:

在调用window.location.replace时会保留pathname部分,history v4.10.1修复了这个问题,使用historyv4.10.1以下版本的开发者需注意这个问题。

3.history.go

其实现与browserHisotry的history.go一致,调用全局的window.history.go方法:

当调用history.go方法时,history的状态更新由hashchange事件监听函数进行处理,具体内容将在2.5.4节介绍。

注意,在Firefox浏览器中,通过widnow.history.go移动指针而改变hash会使得页面重新刷新加载,这与Chrome等浏览器的行为不一致。