在不同的框中按 Enter 时防止按钮上的 onclick 事件触发

Posted

技术标签:

【中文标题】在不同的框中按 Enter 时防止按钮上的 onclick 事件触发【英文标题】:Prevent onclick event on a button from firing when hitting Enter in a different box 【发布时间】:2018-11-19 03:15:24 【问题描述】:

我需要在 SE 编辑器的 #wmd-button-bar 中有一个用户输入字段,以及一个按钮。用户可以在输入字段中输入一些数据,然后按一个按钮来处理该数据。我正在使用用户脚本来实现这一点。我已经创建了一个单独的 MVCE,这里是 Tampermonkey/Greasemonkey 的 direct install link。

要重现该问题,请安装用户脚本。重新加载此页面,然后单击“编辑”。您会注意到一个带有按钮的新空白输入框。将“编辑摘要”框设为空白,将其留空,然后按 Enter。现在,您的插入符号将不再提交答案框,而是专注于新的空白输入框。

如果您在“问题标题”框中按 Enter,也会发生同样的情况。

console.log 消息中,您会注意到按钮上有一个MouseClick 事件!这不是预期的行为。事实上,这怎么可能?我们只是在 Edit summary 框中按 Enter 键,甚至没有触摸新的空白输入或其按钮。那么它是如何注册鼠标点击的呢?

如何解决这个问题?

注意:按钮onclick 处理程序内的e.preventDefault(); 是必需的。否则,当用户按下按钮来处理他们的输入数据时,答案框会自行提交。


The Userscript Code:

function createModal(buttonBar)
    var div = document.createElement("div"),
        input = document.createElement("input"),
        btn = document.createElement("button");

    div.id = "box";

    input.type = "text";

    btn.innerhtml = "Button";
    btn.onclick = function(e)
        e.preventDefault();
        console.log("I was called");
        input.focus();
        console.dir(e);
        console.trace();
    ;

    div.appendChild(input);
    div.appendChild(btn);

    return div;


setInterval(function () 
    var cont = document.querySelector(".wmd-container:not(.processed)"), ul, buttonBar, div;

    if (cont && (ul = cont.querySelector(".wmd-button-bar ul"))) 
        cont.classList.add("processed");

        buttonBar = cont.querySelector("div[id^=wmd-button-bar]");

        div = createModal(buttonBar);
        buttonBar.appendChild(div);
    
, 500)

【问题讨论】:

您是否尝试过定义一个按键事件来按下回车键并将 e.preventDefault() 放入回调中?这可能会有所帮助。 @MarziehBahri 抱歉,我不希望禁用在编辑摘要框中按 Enter 键提交帖子的默认行为。所以,我不能那样做。 一种可能性是 - form 仅包含 input 文本在 Enter 按下时提交。这可能会触发所有提交活动,例如单击。如果是这种情况,那么您可以删除父表单元素或再添加一个隐藏的输入元素。或者添加stopPropagation,通过回车键只触发一个提交事件。 您可以尝试的一个拼凑方法是在输入框上添加一个事件处理程序,用于输入按下,例如 - function preventSubmission(e) e.preventDefault();或者在输入处理程序中设置一个信号量/标志并在点击处理程序中检查它并相应地阻止操作。 【参考方案1】:

它的默认 HTML 行为。 form 中的所有buttons 都属于type="submit"。在按下enter 时,默认情况下会单击form 的最新按钮并调用它们的处理程序。为了解决这个问题,按钮是用type="button" 创建的。

console.log(document.querySelector("#a").type)
console.log(document.querySelector("#b").type)
console.log(document.querySelector("#c").type)
<form>
    <input type="text">
    <button id="a" onclick="console.log('a')">Submit type</button>
    <button id="b" onclick="console.log('b')" type="button">Button type</button>
    <input id="c" type="submit" value="Input Submit type">
</form>

您可以refer this了解&lt;button&gt;&lt;input type="button"&gt;的行为。

如果您只是检查控制台,document.querySelector("#box").children[1].type 将显示为submit

默认情况下,按钮充当submit 类型,除非明确指定(submit(default)/reset/button)。只需运行document.querySelector("#box").children[1].type=button。您会发现它按预期工作。

在跨浏览器中的行为是相同的,并在Firefox Nightly(开发版)、ChromeSafari 和works a little bit different in IE 中进行了测试。

您还可以看到默认情况下点击是console.log(event.detail)0,因为它是在内部触发的。当通过左键单击触发时,它将是1。 MDN Docs on click event

【讨论】:

【参考方案2】:

简短而简单的答案是为您的按钮元素强制键入:

<button type="button"></button>

它默认为type="submit",这就是它采取相应行动的原因。

【讨论】:

这个答案被低估了。【参考方案3】:

我在 Firefox 浏览器中尝试了以下代码,它按预期工作。

function createModal(buttonBar)
    var div = document.createElement("div"),
        input = document.createElement("input"),
        btn = document.createElement("button");

    div.id = "box";

    input.type = "text";
    btn.type = "button";

    btn.innerHTML = "Button";
    btn.onclick = function(e)
        console.log("I was called");
        input.focus();
        console.dir(e);
        console.trace();
    ;

    div.appendChild(input);
    div.appendChild(btn);

    return div;


setInterval(function () 
    var cont = document.querySelector(".wmd-container:not(.processed)"), ul, buttonBar, div;

    if (cont && (ul = cont.querySelector(".wmd-button-bar ul"))) 
        cont.classList.add("processed");

        buttonBar = cont.querySelector("div[id^=wmd-button-bar]");

        div = createModal(buttonBar);
        buttonBar.appendChild(div);
    
, 500);

请注意,我已经设置了btn.type="button";,这确保了表单没有被提交,并且还删除了e.preventDefault();,因为按钮现在永远不会提交表单。

请记住,默认情况下,如果您不将 type 赋予 button 元素,那么它的行为将类似于 submit 按钮。

MouseClick 事件也被触发,因为在提交表单时,在表单中存在的提交按钮上触发了 click 事件。因为你有没有type 属性的按钮,所以它就像一个提交按钮。所以MouseClick 事件在您按下回车时被触发(作为提交表单)。

您可以通过将浏览器开发人员工具中的onclick 处理程序添加到Save edits 提交按钮并在文本字段上按Enter 来验证这一点。

【讨论】:

以上是关于在不同的框中按 Enter 时防止按钮上的 onclick 事件触发的主要内容,如果未能解决你的问题,请参考以下文章

从html输入文本框中按回车键时如何防止回发?

C#:如何在文本框中按下输入触发按钮,但仍允许“Ctrl + A”等快捷方式通过?

如何在extjs组合框中按Enter键获取所选结果的值

当我在文本框中按 Enter 键时发出恼人的哔哔声

当我们从文本框中按 Enter 键时,在单个 jQuery 方法中处理多个操作

当用户在文本框中按下返回时,我可以取消回发吗?