我正在尝试监听浏览器默认上下文菜单(不是自定义上下文菜单)上的“在新选项卡中打开链接”上下文菜单项的单击。我想在页面在新选项卡中打开之前执行一些 JavaScript。或者甚至停止默认行为,执行我的 javascript,然后自己 window.open() 链接。
我已经看到如何监听这样的上下文菜单...
document.addEventListener('contextmenu', e => {});
但这不允许我确定是否单击了特定项目。
那是不可能的。您无法监听每个用户交互,但您可以猜测一些。如果您必须在打开新窗口之前执行操作,请使用自定义上下文菜单。
您可以采取某种解决方法,例如在打开上下文菜单后监听
window.onblur
和/或 window.mousemove
。我遇到过几种情况,我不得不处理与你类似的挑战,但并不是所有的事情都能被捕获。
例如,鼠标移动不会触发,而上下文菜单已打开,但
document.hasFocus()
为 true。一旦用户在上下文菜单中单击,并且鼠标仍在当前文档上方,鼠标移动就会在同一位置触发两次。如果与单击事件结合使用,用户可以通过左键单击 DOM 来关闭上下文菜单。如果用户使用 ESC 关闭上下文菜单,则会触发 keyup,但如果用户使用键盘选择某些内容则不会触发。
/*
auxclick can be any mouse key except primary
contextmenu may also trigger, if you use the contextmenu key on the keyboard
but it fires a MouseEvent with values from a KeyboardEvent
*/
["contextmenu", /*"mousemove", */ "click", "auxclick", "keydown", "keyup"].forEach(name => {
document.addEventListener(name, function(e) {
if (document.visibilityState != "hidden") {
console.log(name, document.hasFocus(), document.activeElement, e.key || e.screenX, e.key || e.screenY);
}
});
});
document.addEventListener("visibilitychange", function(e) {
console.log("visibilitychange", document.hasFocus(), document.visibilityState, window.screenX, window.screenY);
if (window.screenX == window.screenY && window.screenX == -32000 && document.visibilityState == 'visible') {
console.log("restored");
}
});
/*
this won't trigger if the user switches from outside
the window directly into an iframe or between multiple
iframes see https://crbug.com/967430
monitor document.hasFocus() changes and fire a custom focus/blur event on change.
*/
window.addEventListener("focus", function(e) {
console.log("focus", document.hasFocus());
});
window.addEventListener("blur", function(e) {
console.log("blur", document.hasFocus(), document.visibilityState, window.screenX, window.screenY);
setTimeout(() => {
if (document.visibilityState == "hidden") {
if (window.screenX == window.screenY && window.screenX == -32000) {
console.log("minimized");
} else {
console.log("maybe new or other tab with focus or view source?");
}
} else if (!document.hasFocus()) {
if (window == window.top) {
console.log("maybe new window or dev tools");
} else {
console.log("maybe new window, dev tools or I'm an iframe and my parent got selected");
}
} else if (document.hasFocus()) {
console.log("Maybe entered an iframe or canvas?", document.activeElement);
}
}, 1);
});
setInterval(() => console.log("interval", document.hasFocus(), document.activeElement), 2000);