【问题标题】:Reliably change page title in browser history via JavaScript通过 JavaScript 可靠地更改浏览器历史记录中的页面标题
【发布时间】:2016-11-30 12:14:19
【问题描述】:

是否可以在页面加载后通过 JavaScript 更改浏览器历史记录中的页面标题?应该是跨浏览器(当然)并且可以在不支持 HTML5 History API 的浏览器上工作,我的主要目标浏览器是 Chrome。

我尝试了多种方法,但似乎没有一种方法能够可靠地工作。这是我上次尝试过的 (history.js):

<html>
    <head>
        <title>Standard title</title>
        <script src="https://rawgit.com/browserstate/history.js/master/scripts/bundled-uncompressed/html4%2Bhtml5/native.history.js"></script>
    </head>
    <body>
        <script>
            window.setTimeout(function(){
                document.title = "My custom title";
                History.replaceState({}, "My custom title", window.location.href);
            }, 3000);
        </script>
    </body>
</html>

如果我在页面加载后 3 秒内在 Chrom 中加载历史记录页面,我会看到 Standard title,3 秒后我会看到 My custom title

为什么我需要这个:我有一个仅适用于 JavaScript 的应用程序 (Angular 1),它在不同的环境(开发、测试、生产)上运行。我想显示像MyApp (&lt;environmentName&gt;) 这样的标题,但我不想为每个环境构建单独的应用程序版本。相反,应用程序可以通过 AJAX 从后端请求环境信息并更新页面的标题。所有这些都可以正常工作(页面标题已更新),但浏览器历史记录仍显示“标准”标题。

有没有办法在浏览器历史记录中更改页面的标题?

【问题讨论】:

  • 以前我可以通过给document.title赋值来让它工作。但是,我无法再重现工作行为,我不确定它取决于什么要求。
  • @JohnWhite 我观察到它是否有效取决于我实际打开历史页面的时间 - 在标题之前或之后。
  • 那如果你去掉超时,让它在页面加载后立即更新标题,它不会是自动的吗?
  • @RomainFournereau 超时模拟“我们想在某个时间点更改标题”。
  • 注明。我想您将不得不等待 replaceState() 与标题一起使用。否则,我想更残酷的方法是以某种方式返回,然后直接返回页面,更新标题。

标签: javascript angularjs google-chrome browser-history


【解决方案1】:

简短回答:您似乎无法在 Chrome 中为同一网址保留不同的标题记录。

免责声明:我只是偶然发现了这个问题,之前没有任何经验。尽管如此,这个问题是如此清晰有趣,以至于我忍不住做了一些实验:

首先,我同意历史选项卡中显示的历史记录(即页面标题)并不那么可靠(可能是错误或缓存)。

所以我决定查看数据库文件中的 Chrome 历史记录,例如,使用 DB Browser for SQLite

令我惊讶的是,Chrome 历史记录只为每个 url 保留一个版本(最新)的标题。当我执行History.replaceState({}, "My custom title", window.location.href); 时,数据库中的标题确实会更新。

但是,@Bekim 的方法不会更改数据库中的标题。

【讨论】:

  • 那是因为 document.title 是一个 BOM 方法。所有传统和传统浏览器都完全支持该约定 - 并且约定取代任何仲裁标准。问题是:在构思 BOM 时,chrome 并不存在。甚至连 IE 和 FF 都兼容。但是chrome不怪它没有,他们根本就没有那种过去的经验。 !但它确实反映了历史的过去和未来。
【解决方案2】:

问题是replaceState() 的第二个参数,title 参数,目前基本上被所有实现浏览器忽略。但是,pushState 上的第三个参数 url 被考虑在内。不幸的是,它不适用于replaceState(根据我的测试,至少在 Chrome 或 Edge 中不起作用)。

考虑到这一点,从客户端,您可以使用以下解决方法之一,无论您喜欢哪种方式:

history.pushState({}, "", "my-custom-appendix");
history.pushState({}, "", "#my-custom-appendix");

在 Chrome 中,这将创建额外的条目,其标题为 http://myurl/my-custom-appendixhttp://myurl/#my-custom-appendix(分别)。我相信这是您可以从客户端获得的最接近的结果,副作用是您将在浏览器历史记录中获得一个新的历史记录条目——每次访问您的应用程序时,您基本上都会看到(按时间戳递增顺序) ):

即使您将第二个参数设置为非空字符串,您也会将 URL 视为标题(至少我的情况是这样)。


要获得更强大的方法,您需要使用简单的服务器端预处理器 AFAIK,例如 PHP。

【讨论】:

    【解决方案3】:

    与 angularjs 相关:-

    在模块后添加运行方法:-

    .run(function ($rootScope) {

    $rootScope.$on('$stateChangeSuccess', function (evt, toState) {
        window.document.title = toState.title + ' - example.com';
    });
    

    });

    你的状态:-

    .state('productDetail', {

        title: 'Details of selected product',
        url: '/Detail.html',
        templateUrl: '/product-details.html',
        controller: 'ProductDetailsCtrl'
    
      })
    

    .state('categoryManager',{

        title: 'Category Manager',
        url: '/category-Manager.html',
        templateUrl: 'categoryManager.html',
        controller: 'categoryManagerCtrl'
       
      });
    

    这将根据您的状态更改标题。

    【讨论】:

      【解决方案4】:

      这是最简单的事情

      document.title = "My App " +environmentName;
      

      历史记录将立即更新新文档标题。


      为了能够对其进行正面测试,请尝试执行以下几个步骤。

      1st将以下内容复制粘贴到您的控制台并执行:

      name = '{ "location": ["http://stackoverflow.com/questions/12689408/how-can-jquery-window-location-hash-replace","http://stackoverflow.com/questions/12978739/is-there-a-javascript-api-to-browser-history-information-limited-to-current-dom","http://stackoverflow.com/questions/24653265/angular-browser-history-back-without-reload-previous-page"],"title" : ["Page 1", "Page 2", "Page 3"]}';
      
          document.title = "Where We've Started";
      

      2nd 将以下内容复制粘贴到您的控制台并执行 3 次

      nm = JSON.parse(name);
      location = nm.location[0]; 
      

      3rd加载完位置后,立即执行以下操作

      nm = JSON.parse(name);
      document.title = nm.title[0];
      

      每次增加数组索引如下:

      location = nm.location[1];
      document.title = nm.title[1];
      

      (最大索引为 3,例如 num 2)
      然后单击并按住后退按钮以显示最新的历史记录条目,所有这些条目都保持正常和更新,以反映新的文档标题。

      警告:如果在您退回到给定的历史条目后脚本未运行,则页面标题将按预期恢复为现有的硬编码文档标题。但是由于这个历史控件名称将由所有页面中的脚本提供,它们还将继续反映所提供的实时文档标题。这就是人们在回到历史硬编码页面时被欺骗的地方。并想:“该死的:出事了!”

      图 1.:在单独/新窗口上执行的演示代码的最终结果。

      【讨论】:

      • 等一下,这里有些不对劲——document.title 确实 似乎时不时地起作用,但我不确定是什么决定了历史条目实际上已经更新,或者更改只在浏览器标题中生效。
      • 我可以重现以前的工作行为,但现在不行。如果您能解释造成这种情况的原因以及如何克服它,那么您很可能会获得赏金。
      • @JohnWhite - 在这里,让我用 postscriptum 更新我的答案 - 不容易,在 stackoverflow 环境中演示它,但我会尽力提供明确的说明......几秒钟
      • 我使用的是完全相同的 sn-p(分配给 document.title),并且在没有任何修改的情况下更新的标题出现在之前的历史记录中,但现在没有。同样,没有对我的代码进行任何修改,它只是自发地“停止工作”。
      • @JohnWhite 好的,我知道,解释在我附加的解释中——它让你觉得奇怪和意外地恢复到旧标题——但那是因为你已经按原样重新加载了页面而没有修改脚本并且文档标题会立即更新为硬编码。
      【解决方案5】:

      火狐52。琐碎:

      document.title = 'CoolCmd';
      

      Chrome 57 需要一些魔法。此变体也适用于 Firefox 52。它不会在浏览器历史记录中添加不必要的条目。

      // HACK Do not change the order of these two lines!
      history.replaceState(null, '');
      document.title = 'CoolCmd';
      

      MS Edge 14.14393 不允许更改历史记录中文档的标题。他甚至没有将history.pushState()指定的地址添加到历史记录中!哈哈

      我没有测试 Safari...

      【讨论】:

        【解决方案6】:

        您可以使用document.write() 在文档仍在加载时首先将正确的标题写入文档。但它需要向服务器发送同步请求:

        <head>
          <script>
          (function () {
            // Get title using sync request.
            var title = "Value from server";
            document.write("<title>"+ title + "</title>");
          })();
          </script>
        </head>
        

        包含上面截断的页面将在浏览器历史记录中显示“来自服务器的值”标题。

        【讨论】:

        • 我真的很想避免同步请求。我已经尝试过 3 秒超时。如果之前没有设置标题,这似乎非常可靠。但是,如果标题已设置,则在历史记录中不会更改。这种做法似乎和设置document.title的效果一样。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-02
        • 1970-01-01
        • 1970-01-01
        • 2017-10-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多