有两种方法可以更改location.href。您可以编写location.href = "y.html",它会重新加载页面,也可以使用不重新加载页面的历史API。我最近对第一个进行了很多实验。
如果您打开一个子窗口并从父窗口捕获子页面的负载,那么不同的浏览器的行为会非常不同。唯一常见的是,他们删除旧文档并添加新文档,因此例如将 readystatechange 或 load 事件处理程序添加到旧文档没有任何效果。大多数浏览器也会从窗口对象中删除事件处理程序,唯一的例外是 Firefox。在带有 Karma runner 的 Chrome 和 Firefox 中,如果您使用 unload + next tick,您可以在 loading readyState 中捕获新文档。因此,您可以添加例如 load 事件处理程序或 readystatechange 事件处理程序,或者仅记录浏览器正在使用新 URI 加载页面。在带有手动测试的 Chrome 中(也可能是 GreaseMonkey)和在 Opera、PhantomJS、IE10、IE11 中,您无法捕获处于加载状态的新文档。在这些浏览器中,unload + next tick 在页面加载事件触发后几百毫秒调用回调。延迟通常为 100 到 300 毫秒,但opera simetime 为下一个滴答作了 750 毫秒的延迟,这很可怕。因此,如果您希望在所有浏览器中获得一致的结果,那么您可以在加载事件之后执行您想要的操作,但不能保证在此之前不会覆盖该位置。
var uuid = "win." + Math.random();
var timeOrigin = new Date();
var win = window.open("about:blank", uuid, "menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes");
var callBacks = [];
var uglyHax = function (){
var done = function (){
uglyHax();
callBacks.forEach(function (cb){
cb();
});
};
win.addEventListener("unload", function unloadListener(){
win.removeEventListener("unload", unloadListener); // Firefox remembers, other browsers don't
setTimeout(function (){
// IE10, IE11, Opera, PhantomJS, Chrome has a complete new document at this point
// Chrome on Karma, Firefox has a loading new document at this point
win.document.readyState; // IE10 and IE11 sometimes fails if I don't access it twice, idk. how or why
if (win.document.readyState === "complete")
done();
else
win.addEventListener("load", function (){
setTimeout(done, 0);
});
}, 0);
});
};
uglyHax();
callBacks.push(function (){
console.log("cb", win.location.href, win.document.readyState);
if (win.location.href !== "http://localhost:4444/y.html")
win.location.href = "http://localhost:4444/y.html";
else
console.log("done");
});
win.location.href = "http://localhost:4444/x.html";
如果您仅在 Firefox 中运行脚本,那么您可以使用简化版本并捕获处于加载状态的文档,例如,加载页面上的脚本在您记录 URI 更改之前无法离开:
var uuid = "win." + Math.random();
var timeOrigin = new Date();
var win = window.open("about:blank", uuid, "menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes");
var callBacks = [];
win.addEventListener("unload", function unloadListener(){
setTimeout(function (){
callBacks.forEach(function (cb){
cb();
});
}, 0);
});
callBacks.push(function (){
console.log("cb", win.location.href, win.document.readyState);
// be aware that the page is in loading readyState,
// so if you rewrite the location here, the actual page will be never loaded, just the new one
if (win.location.href !== "http://localhost:4444/y.html")
win.location.href = "http://localhost:4444/y.html";
else
console.log("done");
});
win.location.href = "http://localhost:4444/x.html";
如果我们谈论的是改变 URI 的哈希部分的单页应用程序,或者使用历史 API,那么您可以分别使用窗口的 hashchange 和 popstate 事件。即使您在历史记录中前后移动,直到您停留在同一页面上,这些也可以捕获。文档不会被这些更改,页面也没有真正重新加载。