我正在为某个网站编写Greasemonkey脚本,该脚本在某些时候会修改location.href
。
如果页面上window.addEventListener
发生更改,我怎样才能收到活动(通过window.location.href
或类似内容)?我还需要访问指向新/修改的URL的文档的DOM。
我见过其他涉及超时和投票的解决方案,但如果可能,我想避免这种情况。
答案 0 :(得分:53)
当活动历史记录条目更改时会触发popstate事件。 [...] popstate事件只能通过执行浏览器操作来触发,例如单击后退按钮(或在JavaScript中调用history.back())
因此,在使用popstate
时收听popstate
事件并发送history.pushState()
事件应足以对href
更改采取措施:
window.addEventListener('popstate', listener);
const pushUrl = (href) => {
history.pushState({}, '', href);
window.dispatchEvent(new Event('popstate'));
};
答案 1 :(得分:20)
您无法避免轮询,href更改没有任何事件。
如果你不过分,使用间隔是非常轻的。如果你担心的话,每50ms左右检查一次href对性能没有任何重大影响。
答案 2 :(得分:10)
我在我的扩展程序中使用此脚本" Grab Any Media"并且工作正常(像youtube case )
var oldHref = document.location.href;
window.onload = function() {
var
bodyList = document.querySelector("body")
,observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (oldHref != document.location.href) {
oldHref = document.location.href;
/* Changed ! your code here */
}
});
});
var config = {
childList: true,
subtree: true
};
observer.observe(bodyList, config);
};
答案 3 :(得分:9)
您可以使用默认的onhashchange
事件。
可以像这样使用:
function locationHashChanged( e ) {
console.log( location.hash );
console.log( e.oldURL, e.newURL );
if ( location.hash === "#pageX" ) {
pageX();
}
}
window.onhashchange = locationHashChanged;
如果浏览器不支持oldURL
和newURL
,您可以像这样绑定它:
//let this snippet run before your hashChange event binding code
if( !window.HashChangeEvent )( function() {
let lastURL = document.URL;
window.addEventListener( "hashchange", function( event ) {
Object.defineProperty( event, "oldURL", { enumerable: true, configurable: true, value: lastURL } );
Object.defineProperty( event, "newURL", { enumerable: true, configurable: true, value: document.URL } );
lastURL = document.URL;
} );
} () );
答案 4 :(得分:7)
你有没有试过beforeUnload? 此事件在页面响应导航请求之前立即触发,这应包括修改href。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
<TITLE></TITLE>
<META NAME="Generator" CONTENT="TextPad 4.6">
<META NAME="Author" CONTENT="?">
<META NAME="Keywords" CONTENT="?">
<META NAME="Description" CONTENT="?">
</HEAD>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
$(window).unload(
function(event) {
alert("navigating");
}
);
$("#theButton").click(
function(event){
alert("Starting navigation");
window.location.href = "http://www.bbc.co.uk";
}
);
});
</script>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#FF0000" VLINK="#800000" ALINK="#FF00FF" BACKGROUND="?">
<button id="theButton">Click to navigate</button>
<a href="http://www.google.co.uk"> Google</a>
</BODY>
</HTML>
但请注意,无论是因为脚本还是有人点击链接,您的活动都会在 时触发您离开页面。 您真正面临的挑战是检测事件被触发的不同原因。 (如果这对你的逻辑很重要)
答案 5 :(得分:2)
通过 Jquery ,试试
$(window).on('beforeunload', function () {
//your code goes here on location change
});
使用 javascript :
window.addEventListener("beforeunload", function (event) {
//your code goes here on location change
});
参考文件:https://developer.mozilla.org/en-US/docs/Web/Events/beforeunload
答案 6 :(得分:1)
有两种方法可以更改location.href
。您可以编写location.href = "y.html"
来重新加载页面,也可以使用历史记录API来重新加载页面。我最近尝试了很多。
如果打开子窗口并从父窗口捕获子页面的负载,则不同的浏览器的行为会大不相同。唯一常见的是,它们删除了旧文档并添加了一个新文档,因此,例如,将readystatechange或load事件处理程序添加到旧文档中没有任何作用。大多数浏览器也会从window对象中删除事件处理程序,唯一的例外是Firefox。如果使用unload + next tick
,则在带有KarmaRunner的Chrome和Firefox中,可以在加载readyState中捕获新文档。因此,您可以添加例如加载事件处理程序或readystatechange事件处理程序,或者仅记录浏览器正在使用新URI加载页面。在具有手动测试功能的Chrome中(也可能是GreaseMonkey),在Opera,PhantomJS,IE10,IE11中,您无法在加载状态下捕获新文档。在这些浏览器中,unload + next tick
在页面的加载事件发生后几百毫秒后调用回调。延迟通常为100到300毫秒,但是歌剧simetime对于下一个滴答声会产生750毫秒的延迟,这很可怕。因此,如果要在所有浏览器中获得一致的结果,则可以在load事件之后执行所需的操作,但是不能保证在此之前不会覆盖该位置。
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
事件。即使您在历史记录中来回移动,直到您停留在同一页面上,它们也可以捕获。这些文档不会更改,页面也不会真正重新加载。
答案 7 :(得分:1)
根据“Leonardo Ciaccio”的回答,修改后的代码在这里: 即删除 for 循环并在删除时重新分配 Body 元素
window.addEventListener("load", function() {
let oldHref = document.location.href,
bodyDOM = document.querySelector("body");
const observer = new MutationObserver(function(mutations) {
if (oldHref != document.location.href) {
oldHref = document.location.href;
console.log("the location href is changed!");
window.requestAnimationFrame(function() {
let tmp = document.querySelector("body");
if(tmp != bodyDOM) {
bodyDOM = tmp;
observer.observe(bodyDOM, config);
}
})
}
});
const config = {
childList: true,
subtree: true
};
observer.observe(bodyDOM, config);
}, true);
答案 8 :(得分:0)
试试这个脚本,它可以让你在 URL 改变时运行代码(没有页面加载,就像单页应用程序一样):
var previousUrl = '';
var observer = new MutationObserver(function(mutations) {
if (location.href !== previousUrl) {
previousUrl = location.href;
console.log(`URL changed to ${location.href}`);
}
});