当超链接行为由例如虚拟创建时,如何防止打开新选项卡或窗口? HTML 按钮的“点击”事件处理?
Posted
技术标签:
【中文标题】当超链接行为由例如虚拟创建时,如何防止打开新选项卡或窗口? HTML 按钮的“点击”事件处理?【英文标题】:How does one prevent the opening of a new tab or window when hyperlink behavior was created virtually by e.g. an HTML button's "click" event handling? 【发布时间】:2021-11-11 12:15:50 【问题描述】:我可以通过删除target
属性来禁用在<a>
标签的情况下打开新选项卡或窗口,例如target='_blank'
在某些情况下,而不是 <a>
网站放置 <button>
并添加 onClick()
或 submit()
等以编程方式生成链接并设置 target
属性。
<button id="653cde4c-1620-11ec-85b5-5ae26c154b46">
<div>click here</div>
</button>
在一些webpack 生成的javascript 文件中会有类似的东西不容易找到和阅读缩小的代码。
var button = document.querySelctor('653cde4c-1620-11ec-85b5-5ae26c154b46')
// Add whatever you want to add to this button element, e.g. add onClick() or submit() or something else which I am not sure of
我们可以在https://i.stack.imgur.com/8oG5w.png看到图片
在<button>
提供链接点击功能的情况下。我无法查看和编辑 onClick()
或 submit()
等,因为它的 webpack 生成了 javascript。我只能在 devtools console
中加载该 webapge 后运行我的 javascript 代码。
在这种情况下如何禁用打开新标签页或浏览器新窗口?或者我应该运行什么 javascript 代码来覆盖 <button>
链接行为?
【问题讨论】:
return false
在事件处理程序中?
查看link。
我认为 OP 想要禁用打开新标签/窗口,而不是阻止点击 @DominikMatis
是否至少有任何模式(例如具有至少一个特定属性的特定元素)可以识别这样的触发器/这样的元素?
@PeterSeliger:我不确定,我添加了截图和编辑问题
【参考方案1】:
根据基于 webpack 的代码如何管理资源的选项卡处理,一种可能的解决方案是将自己的代码包装在 window.open
周围,甚至完全用自己的实现替换它。
至于包装,根据截获的数据,可以决定是否完全抑制 url 处理,或者不打开新标签/窗口,而是转发到 location.href
,甚至继续调用原window.open
。
// untouchable 3rd party code
//
function alienLocationHandler( currentTarget )
let url, target = currentTarget.dataset;
url = (url ?? '').trim();
if (url)
target = (target ?? '').trim();
if (target)
// due to SO's permission handling ...
//
// ... Blocked opening 'https://***.com/' in a
// new window because the request was made in a sandboxed
// frame whose 'allow-popups' permission is not set.
//
window.open(url, target);
else
window.location.href = url;
document
.querySelectorAll('[data-url]')
.forEach(elmNode =>
elmNode.addEventListener('click', alienLocationHandler)
);
// one possible approach :: wrap around `window.open`
//
window.open = (function createAroundHandler(proceed, thisArg)
return function aroundWindowOpen(url, target, ...rest)
console.log('aroundWindowOpen ...',
url,
target,
rest,
);
// - of cause all the code is just for demonstration purpose.
//
// - the OP has to come up with own handler logic which does
// fit the OP's needs best.
if (url !== 'https://***.com')
// invocation of the original `window.open`
// will be blocked by SO's permission handling.
proceed.call(thisArg, url, target, ...rest);
else
// delayed fowarding to `location.href`.
setTimeout(() => window.location.href = url , 5000);
;
(window.open, window));
body margin: 0;
.as-console-wrapper min-height: 87%; top: auto;
<button data-url="https://***.com">
no interception
</button>
<button
data-url="https://google.com"
data-target='google'
>
intercepted & open attempt
</button>
<button
id="_653cde4c-1620-11ec-85b5-5ae26c154b46"
data-url="https://***.com"
data-target='_blank'
>
intercepted and forwarded with 5sec delay
</button>
另一种方法是通过监听和处理click
事件来利用event delegation,例如document.body
级别。
// untouchable 3rd party code
//
function alienLocationHandler( currentTarget )
let url, target = currentTarget.dataset;
url = (url ?? '').trim();
if (url)
target = (target ?? '').trim();
if (target)
// due to SO's permission handling ...
//
// ... Blocked opening 'https://***.com/' in a
// new window because the request was made in a sandboxed
// frame whose 'allow-popups' permission is not set.
//
window.open(url, target);
else
window.location.href = url;
document
.querySelectorAll('[data-url]')
.forEach(elmNode =>
elmNode.addEventListener('click', alienLocationHandler)
);
// another possible approach :: event delegation
//
// - [https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_delegation]
// - [https://davidwalsh.name/event-delegate]
//
// - [https://javascript.info/event-delegation]
// - [https://learn.jquery.com/events/event-delegation/]
//
function isButtonEvent(activeElement, targetNode)
return (activeElement.tagName.toLowerCase() === 'button') && (
activeElement.isSameNode(targetNode) ||
activeElement.contains(targetNode)
);
function preventSpecificButtonClickBehavior(evt)
const elmButton = document.activeElement;
if (isButtonEvent(elmButton, evt.target))
const url = (elmButton.dataset.url ?? '').trim();
const isUrlBasedPrevented = (url !== 'https://***.com');
const isIdBasedPrevented = ((elmButton.id ?? '').trim() !== '');
if (isUrlBasedPrevented || isIdBasedPrevented)
evt.stopImmediatePropagation();
evt.stopPropagation();
if (isUrlBasedPrevented)
console.log('prevented button click behavior ... URL based')
if (isIdBasedPrevented)
console.log('prevented button click behavior ... ID based')
document
.body
.addEventListener(
'click',
preventSpecificButtonClickBehavior,
// - [https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#parameters]
// - The boolean `useCapture` parameter/flag does the trick if set as `true` value.
true
);
body margin: 0;
.as-console-wrapper min-height: 87%; top: auto;
<button data-url="https://***.com">
click behavior not prevented
</button>
<button
id="_653cde4c-1620-11ec-85b5-5ae26c154b46"
data-url="https://***.com"
>
prevented behavior (id based)
</button>
<button
data-url="https://google.com"
data-target='google'
>
<span>
<span>
prevented behavior (url based)
</span>
</span>
</button>
【讨论】:
@AlokSinghMahor ...关于上述两种方法还有什么问题吗? 非常感谢您的回答。这个答案给了我线索来建立解决我的问题。我对你的答案投了赞成票。你的方法可以帮助我解决我在<button>
中没有data-url
的问题吗?请看截图
@AlokSinghMahor ...我想您谈论的是基于事件委托的方法。 data-*
属性仅用于演示目的,以模仿第三方按钮单击触发的超链接行为。因此,您需要自己弄清楚如何最好地识别事件源,然后必须通过进一步传播事件来停止该事件源。一个可行的识别可能已经是检查按钮的特殊模式id
' 与这种按钮的结构相结合,就像总是有一个<div/>
和另一个id
属性嵌入在<button/>
中。 【参考方案2】:
onClick()
中的逻辑可能类似于window.open(url, [params])
。您可以将其更改为设置window.location.href = url;
,并且URL将在同一窗口中加载。
【讨论】:
我们不知道url
的价值
@AlokSinghMahor url
是您点击时要访问的 URL
对于外部网站,我无权查看和编辑 onClick()。加载到 devtools 控制台后,我只能在该 webapge 上运行我的 javascript 代码。以上是关于当超链接行为由例如虚拟创建时,如何防止打开新选项卡或窗口? HTML 按钮的“点击”事件处理?的主要内容,如果未能解决你的问题,请参考以下文章