通过JavaScript可靠地更改浏览器历史记录中的页面标题

14

页面加载后,是否可以通过JavaScript更改浏览器历史记录中的页面标题?应该是跨浏览器(当然),并且适用于不支持HTML5历史记录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秒内在Chrome中加载历史页面,我会看到“标准标题”,3秒后我会得到“我的自定义标题”。
为什么需要这个:我有一个仅使用JavaScript的应用程序(Angular 1),可以在不同的环境(开发,测试,生产)上运行。我想显示一个标题,例如MyApp (<environmentName>),但我不想为每个环境构建单独的应用程序版本。相反,应用程序可以通过AJAX从后端请求环境信息并更新页面的标题。所有这些都很好(页面标题得到更新),但浏览器历史仍然显示“标准”标题。
有没有办法在浏览器历史中更改页面的标题?

以前我只需将一个值分配给 document.title 就能让它起作用。然而,我现在无法再次重现这种工作行为,也不确定它依赖于什么要求。 - John Weisz
1
@JohnWhite 我注意到它的工作或不工作取决于我何时打开历史记录页面 - 是在标题说出之前还是之后。 - lexicore
那如果您移除超时并让它在页面加载后立即更新标题,这不就自动了吗? - Romain
@RomainFournereau 超时模拟“我们想在某个时间点更改标题”。 - lexicore
知道了。我猜你得等replaceState()和title一起工作。 否则,我想一个更暴力的方法是先回退,然后立即返回页面,更新标题。 - Romain
@RomainFournereau 目前看来唯一可靠的方法是在服务器端呈现标题。 - lexicore
6个回答

3
简短回答:在Chrome中,似乎没有办法为同一URL保留不同的标题记录。
免责声明:我刚刚偶然发现了这个问题,并没有先前的经验。尽管如此,这个问题非常清晰和有趣,我忍不住进行了一些实验:
首先,我同意历史记录(即页面标题)在历史选项卡中显示并不可靠(可能是一个错误或缓存)。
所以我决定查看Chrome历史记录的数据库文件,例如使用DB Browser for SQLite
令人惊讶的是,Chrome历史记录只保留每个URL的一个版本(最新版本)的标题。当我执行History.replaceState({}, "My custom title", window.location.href);时,标题确实在数据库中更新。
但是,@Bekim的方法不会更改数据库中的标题。

这是因为document.title是一个BOM方法。所有传统和常规浏览器都完全支持这个约定 - 约定优于任何仲裁标准。问题是:当BOM被构思时,Chrome还不存在。甚至IE和FF也是兼容的。但Chrome不应受到责备,它们只是没有那种过去的经验。但它确实反映了历史的回顾和前瞻。 - Bekim Bacaj

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作为标题查看该URL。


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


1
火狐浏览器52。琐碎:
document.title = 'CoolCmd';

Chrome 57 需要一些特殊操作。此变体也适用于 Firefox 52。它不会向浏览器历史记录中添加不必要的条目。
// HACK Do not change the order of these two lines!
history.replaceState(null, '');
document.title = 'CoolCmd';

微软 Edge 14.14393 不允许在历史记录中更改文档标题。它甚至不会将由 history.pushState() 指定的地址添加到历史记录中!笑死了

我没有测试过 Safari...


1

那是最容易的事情了

document.title = "My App " +environmentName;

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

为了能够进行积极的测试,请尝试按照以下步骤操作:

第一步:将以下内容复制并粘贴到您的控制台中,并执行:

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";

第二步 将以下内容复制粘贴到您的控制台并执行3次

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

第三步 位置加载完毕后,执行以下操作

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

每次增加数组索引,如下所示:

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

(最大索引为3,例如数字2)
然后单击并按住“后退”按钮以显示最新的历史记录条目,所有信息都是合理的,并按顺序更新以反映新文档标题。

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

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

enter image description here


请稍等一下,这里似乎有些不对劲-- document.title 有时确实有效,但我不确定是什么决定了历史记录条目是否实际更新,或者更改只在浏览器标题中生效。 - John Weisz
我之前可以重现工作行为,但现在不行了。如果您能解释是什么原因导致了这种情况,并且告诉我如何克服它,那么您很可能会得到奖励。 - John Weisz
我正在使用完全相同的代码片段(将值赋给document.title),之前更新后的标题在历史记录中显示,但现在不行了。再次强调,我的代码没有做任何修改,它只是突然“停止工作”了。 - John Weisz
@JohnWhite 好的,我知道了。解释在我的附加说明中 - 它让你感到毛骨悚然和意外,回归旧标题 - 但那是因为你重新加载了页面而没有进行脚本修改,文档标题会立即更新为硬编码标题。 - Bekim Bacaj
很抱歉,我无法确认设置 document.title 是否有效。这里有一个示例。5秒后,“原始标题”将被修改为“修改后的标题”。历史记录条目保持不变 - 至少在Chrome浏览器中是如此。 - lexicore
显示剩余4条评论

1

与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'
   
  });

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

0

在页面加载时,您可以使用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 相同的效果。 - lexicore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接