打印

BW1010: Chrome Safari 中页面文档树建立完毕后通过 document.write 系列方法重写文档不记录到历史记录中

作者:钱宝坤

标准参考

无。

问题描述

document.write 与 document.writeln 方法的作用是向打开的文档流中写入内容,并产生一个文档1

History2 历史记录对象属于 BOM (Browser Object Model) 范畴,他是浏览器访问页面记录的集合。在现行规范中没有对 History 对象进行明确约定,他由各浏览器自行实现。

当使用 write 系列方法向打开的文档流中写入内容后,并没有规范规定浏览器本身的历史记录是否会记录这次文档变更内容。

这个情况已经超出现有标准规范说明内容范畴,各个浏览器对此实现并不一致。

【注1】:在初始文档流还未关闭的情况下只是向文档流中输出内容,不会产生新 document。
write 和 writeln 方法的标准说明请参考现行的 DOM-Level-2 HTML 规范标准: 1.5. Objects related to HTML documents

【注2】:在现有 HTML5 草案中存在 History 对象接口说明: 5.4.2 The History interface

造成的影响

Chrome Safari 中当正常输出文档流关闭后,再通过 document.write 方法重写文档内容,该内容不会记录到历史记录中。

这可能导致用户使用浏览器的后退、前进按键或开发者使用 History 对象的 go 、back、forward 等导航历史记录的方法将不可能再访问到被 write 系列方法重写的页面。

受影响的浏览器

Chrome Safari  

问题分析

根据描述情况,构造测试用例如下:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script>
window.onload = function(){
  function getHTML(){
    return '<!DOCTYPE html>\
      <html>\
      <head>\
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>\
      </head>\
      <body>\
      <h2>执行 $write 方法以后的页面<\/h2>\
      <button onclick="history.back()">后退到上一历史记录页面</button>\
      </body>\
      </html>';
  }
  function echo(type){
    type = type?"writeln":"write";
    document.open();
    document[type](getHTML().replace(/\$write/,type));
    document.close();
  }
  window["test_echo"] = echo;
}
</script>
</head>
<body>
<h2>初始的页面</h2>
<button onclick="test_echo()">使用 wirte 方法重写页面</button>
<button onclick="test_echo(1)">使用 wirteln 方法重写页面</button>
<button onclick="history.forward()">前进到下一历史记录页面</button>
</body>
</html>

例子中分别使用 document.write 和 document.writeln 方法来构造新页面,并使用了 history.forward 和 history.back 方法导航浏览器的历史记录。

在执行此例前请先将浏览器导航到 http://www.google.com 站点,使其拥有可后退的浏览器访问历史记录。

最终各浏览器运行结果如下:

  IE6 IE7 IE8 Firefox Opera Chrome Safari
write 新页面内点击"后退到上一历史记录页面"按钮 初始页 Google 首页 Google 首页
初始页内点击"前进到下一历史记录页面"按钮 wirte 操作后页面 无效 无效
回到 google 首页使用前进历史记录 初始页 初始页 write 操作后页面

通过上表可见:

  • IE6 IE7 IE8 Firefox Opera 中,浏览器历史记录的顺序为:Google 首页--> 原页面 --> write 后页面; 执行 write 操作后产生的新页面被记录到历史记录中
  • Safari 中,浏览器历史记录的顺序为:Google 首页--> 被 write 后新页面 ;执行 write 操作后产生的新页面不被新记录到浏览器历史记录中,而是将原页面的访问历史替换
  • Chrome 中,浏览器历史记录的顺序为:Google 首页--> 原页面;执行 write 操作后产生的新页面不被新记录到浏览器历史记录中,这个新页面也不会替换原始页面的访问历史。

解决方案

不要期望 document.write、document.writeln 操作后浏览器依旧保留该页面的历史记录1,建议只在不依赖历史记录导航的应用需求中使用 document.write、document.writeln 方法。

【注1】:即使在 write 操作后的新页面里使用 location.hash 方法为 URL 加入锚点迫使浏览器记录浏览历史,也无法阻止 Safari 浏览器对原始页面历史记录的替换,同时还会导致 Chrome Firefox 历史记录访问出现新问题。

参见

知识库

相关问题

测试环境

操作系统版本: Windows 7 Ultimate build 7600
浏览器版本: IE6
IE7
IE8
Firefox 3.6.8
Chrome 7.0.517.0 dev
Safari 5.0.2 
Opera 10.62
测试页面: write_and_history.html
本文更新时间: 2010-09-14

关键字

Document Write History Webkit Chrome Safari 历史记录 后退