IE10中的HTML5历史记录
IE10中的HTML5历史记录
构建快速且功能强大的网站是大多数 Web 开发人员都熟悉的挑战。每次用户单击链接时都加载一个新页面速度很慢。动态获取所有内容实际上会禁用后退按钮。使用哈希更好,但仍不理想。Windows 开发者预览版中的 Internet Explorer 10 通过添加对HTML5 History的支持,消除了这种妥协。pushState
、replaceState
和popstate
API 提供了对后退按钮行为以及为动态内容呈现给用户的 URL 的精细控制。这些 API 共同帮助您提高网站性能,而不会牺牲可用性。
如果您还不熟悉 HTML5 History API,请将pushState
视为导航到另一个页面的动态等效项。同样,replaceState
非常类似于location.replace
。区别在于,这些 API 在更新会话历史记录时不会破坏当前页面,而是通过存储状态而不是页面。pushState
和replaceState
都接受三个参数:一个数据对象、一个标题和一个可选的 URL。
history.pushState(data, title, url); history.replaceState(data, title, url);
请注意,大多数浏览器(包括 IE10)都会忽略pushState
和replaceState
的标题参数。如果愿意,您仍然可以提供此信息,因为将来的浏览器可能会将其作为其历史记录 UI 的一部分公开。
设置自定义 URL
pushState
和replaceState
的 URL 参数可用于在不导航的情况下更新页面 URL。为了说明这一点,假设您已加载“http://www.contoso.com/index.html”。使用哈希更改,您只能追加到 URL
// Change to "http://www.contoso.com/index.html#about.html"
location.hash = "about.html";
但使用pushState
和replaceState
,您可以指向您网站上的完全不同的页面,而无需实际访问它。
// Change to "http://www.contoso.com/about.html"
history.pushState(null, "About", "/about.html");
确保您的服务器能够处理您创建的所有动态 URL,以便收藏夹等功能仍然正常工作。您还可以向状态对象添加一些数据,这样以后就不必解析整个 URL 来恢复状态。
history.pushState("about.html", "About", "/about.html");
协议、主机名和端口必须与当前 URL 匹配,但路径、查询和片段可以自定义。这使得将动态状态与易于由服务器支持并且在脚本禁用时也能正常工作的 URL 相关联。最终,这使您能够动态地仅获取和显示从页面到页面发生变化的数据,同时保持用户体验完好无损。
恢复已保存的状态
在导航历史记录(例如,当用户按下后退按钮)或重新加载页面后,您应该恢复状态。通过侦听popstate 事件
来完成状态恢复。当状态由于历史记录导航而更改时,会触发popstate 事件
。此时,可以通过history.state
检索目标状态的数据对象。在页面重新加载的情况下,popstate 事件
不会触发,但仍然可以随时在加载期间或甚至加载后访问history.state
。因此,如下代码可以在适当的时间恢复状态:
function init() {
/* ... */
// Handle page load and reload
loadState();
// Listen for history navigations (e.g. the back button)
window.addEventListener("popstate", loadState, false);
}
function loadState() {
// Grab the data for the current state so we can restore it
var state = history.state;
/* ... */
}
init();
存储复杂、动态的数据
存储在状态中的数据对象不仅仅是一个字符串。还可以使用自定义 JavaScript 对象甚至某些本机类型(如ImageData
)。提供的数据使用结构化克隆算法进行保存,该算法可以保留复杂的关联,如循环和对同一对象的多个引用。这使得保存和恢复即使是复杂对象也变得轻而易举,如这个简单的演示所示。在演示中,通过如下代码捕获画布快照以创建撤销堆栈:
function init() {
/* ... */
// Handle page load and reload
loadState();
// Listen for history navigations (e.g. the back button)
window.addEventListener("popstate", loadState, false);
}
/* ... */
function stopDrawing() {
// Take a snapshot of the current state as an ImageData instance
var state = context.getImageData(0, 0, canvas.width, canvas.height);
history.pushState(state, "");
/* ... */
}
function loadState() {
// Grab the data for the current state so we can restore it
var state = history.state;
/* ... */
if (state) {
// Restore the canvas to our saved ImageData state
context.putImageData(state, 0, 0);
}
}
要更改此设置以跟踪当前状态而不跟踪每个更改,可以使用replaceState
而不是pushState
。
大小注意事项
如果不小心,HTML5 History 会轻松地将大量数据推入堆栈。例如,上面的撤销演示每个状态存储约 0.5MB,如果画布更大,很容易使用更多。只要关联的状态条目保留在会话历史记录中,这些数据就会占用内存,即使在用户离开您的网站后很长时间也是如此。您存储的数据越多,浏览器就越有可能开始清除您的条目以节省空间。此外,一些浏览器还对单次调用pushState
或replaceState
可以存储的数据量强制执行硬限制。
跨浏览器考虑
一如既往,使用功能检测来处理浏览器之间支持的差异。由于 HTML5 History 的大部分涉及事件和属性,真正需要检测的新部分仅限于对pushState
和replaceState
的调用。
function stopDrawing() {
var state = context.getImageData(0, 0, canvas.width, canvas.height);
if (history.pushState)
history.pushState(state, "");
/* ... */
}
这种检测至少可以防止您的脚本在旧浏览器中失败。根据您的场景,您可能希望从全页导航开始,并在支持 HTML5 History 时升级到动态内容。或者,您可以使用历史记录框架或polyfill来保持后退按钮正常工作,但请记住,并非所有内容都可以模拟。例如,对 URL 的路径和查询组件的动态控制只能通过pushState
和replaceState
来实现。
请注意,某些浏览器支持 HTML5 History 的早期版本,与当前版本有两个显著区别:
popstate
事件在页面加载期间也会触发。history.state
属性不存在。
为了支持这些浏览器,您可以回退到从popstate
事件本身读取状态信息。
总结
总而言之,HTML5 History API 为构建响应式和可用的 Web 网站提供了极大的灵活性。只要对旧浏览器有所注意,这些 API 今天就可以被有效地使用。在Windows 开发者预览版的 IE10 中开始在您的网站上测试它们,并通过 Connect 发送反馈。