越来越多的应用使用 Ajax 请求数据,浏览器 URL 不会发生任何变化。同时,浏览的页面内容在用户下次使用 URL 访问时将无法重新呈现,使用路由可以很好地解决这个问题。
单页面利用了 JavaScript 动态变换网页内容,避免了页面重新加载;路由这提供了浏览器地址变化,网页内容页跟随变化,两个结合提供了体验良好的 单页面应用。
路由需要实现以下功能:
在单页面 web 网页中,单纯的浏览器地址改变,网页不会重载,如单纯的 hash 网址改变网页不会变化,因此路由主要通过监听事件,并利用 JavaScript 实现动态改变网页内容,有以下实现方法:
二者的区别是 hash 会在浏览器地址后面增加 #
,而 history 可以自定义地址。
使用 window.location.hash
属性及窗口的 onhashchange
事件 (opens new window),可以实现监听浏览器地址 hash 值变化,执行相应的 JavaScript 切换网页。一些需要注意的地方:
#
以及后面的字符,也叫散列值 https://cellinlab.xyz/#/home
的 hash 即 #/home
window
的 hashchange
事件,当散列值改变时,可以通过 location.hash
来获取和设置 hash 值location.hash
值的变化会直接反应到浏览器的地址栏window.location.hash
值的变化,从而触发 onhashchange
事件https://cellinlab.xyz/#/home
,此时按下回车,浏览器发送 https://cellinlab.xyz/
请求到服务器,请求完毕之后设置散列值为 #/home
,此时触发 onhashchange
事件onhashchange
事件html
中 <a>
标签的属性 href
可以设置为页面的元素 ID 如 #top
,当点击链接时页面跳转到该 ID 元素所在区域,同时浏览器自动设置 window.location.hash
属性,地址栏中的哈希值也会发生变化,并触发 onhashchange
事件window.location.hash = 'home';
let hash = window.location.hash; // '#home'
window.addEventListener('hashchange', function () {
console.log('hashchange');
});
window.history
属性指向 History 对象 (opens new window),它表示当前窗口的浏览历史,当发生改变时,只会改变页面的路径,不会刷新页面history.length
获知当前窗口访问过的页面数量History 对象主要有两个属性:
History.length
当前窗口访问过的页面数量(含当前页面)History.state
History 堆栈最上层的状态值history.length; // 1
history.state; // undefined
History.back()
移动到上一个网址,相当于点击浏览器后退键,该方法对于第一个访问的页面无效 History.forward()
移动到下一个网址,相当于点击浏览器前进键,该方法对于最后一个访问的页面无效History.go()
接收一个整数作为参数,以当前网址为基准,移动到参数指定的网址 history.back();
history.forward();
history.go(1); // 相当于 history.forward()
history.go(-1); // 相当于 history.back()
history.go(0); // 相当于刷新当前页面
History.pushState()
用于在历史中添加一条记录
pushState()
不会触发页面刷新,只是导致 History 对象发生变化,地址栏会有变化history.pushState(obj, title, url)
obj
一个对象,通过 pushState
可以将该对象内容传递到新页面中,不需要是可以填 null
title
指标题,但多数浏览器不支持,建议传空字符串url
新的网址,必须与当前页面处于同一个域,不指定的话则为当前路径,如果设置一个跨域网址会报错const data = { foo: 'bar' };
history.pushState(data, '', '/about.html');
console.log(history.state); // { foo: 'bar' }
pushState
的 URL 参数设置了一个新的锚点值(即 hash),并不会触发 hashchange
事件。相反,如果 URL 的锚点值变了,会在 History 对象创建一条浏览记录。pushState()
方法设置了一个跨域网址,会报错History.replaceState()
用来修改 History 对象的当前记录,用法与 pushState
相同
popstate()
每当 History 对象出现变化时,就会触发 popstate
事件
pushState()
方法或 replaceState()
方法,并不会触发该事件history.back()
、 history.forward()
、 history.go()
方法,才会触发该事件popstate
事件