禁用输入框上的事件

282

显然,一个禁用的 <input> 并不会被任何事件处理。

是否有一种方法可以解决这个问题?

<input type="text" disabled="disabled" name="test" value="test" />
$(':input').click(function () {
    $(this).removeAttr('disabled');
})

这里,我需要点击输入框以启用它。但如果我没有激活它,那么该输入框不应该被提交。


1
这里有一个不错的替代方案:http://blog.pengoworks.com/index.cfm/2010/4/23/Attaching-mouse-events-to-a-disabled-input-element - user479728
您可以使用CSS-pretend-disable,并在onSubmit处理程序中循环遍历输入,真正禁用未激活的输入。 - ptrk
3
读者们请注意:如果您不介意输入被发布,只需使用readonly而不是disabled。我知道这不是OP所要求的,但可能有人和我处于同样的情况... - Hache_raw
12个回答

304

禁用元素不会触发鼠标事件。 大多数浏览器会将源自禁用元素的事件向上传递到DOM树,因此可以在容器元素上放置事件处理程序。 然而,Firefox不表现出这种行为,当您单击禁用元素时,它什么也不做。

我想不出更好的解决方案,但为了完全跨浏览器兼容性,您可以在禁用输入前面放置一个元素,并捕获该元素上的单击事件。 下面是我所说的示例:

<div style="display:inline-block; position:relative;">
  <input type="text" disabled />
  <div style="position:absolute; left:0; right:0; top:0; bottom:0;"></div>
</div>​

jq:

$("div > div").click(function (evt) {
    $(this).hide().prev("input[disabled]").prop("disabled", false).focus();
});​

示例: http://jsfiddle.net/RXqAm/170/ (已更新为使用jQuery 1.7和prop代替attr)。


3
小事情提醒:如果您使用 disabled 属性且没有赋值,那意味着您正在使用 HTML 而不是 XHTML,此时结束斜杠是不必要的。 - Tim Down
11
@Tim:确实没有必要,但它仍然是有效的HTML。这只是一种习惯而已,我觉得这样看起来更好。 - Andy E
3
这不合理:任何其他HTML元素都可以处理鼠标事件,为什么禁用的元素不能(例如mouseenter等)? - Augustin Riedinger
21
在你的CSS中加入input[disabled] {pointer-events:none}可以防止禁用的元素将你的点击“扔掉”。然后,点击的行为就像你点击了父元素一样。在我看来,这是最简单、最干净的解决方案,但不幸的是,它只适用于支持pointer-events CSS属性的浏览器:http://caniuse.com/#search=pointer-events - Doin
1
你可以使用CSS的before选择器来实现相同的结果,而无需添加另一个div。例如:input::before { bottom: 0; content: ''; left: 0; position: absolute; right: 0; top: 0; } - Christophe Geers
显示剩余9条评论

111

在某些浏览器中,禁用的元素会“吞噬”点击事件 - 它们既不响应它们,也不允许它们被任何元素或其容器上的事件处理程序捕获。

在我看来,“修复”这个问题(如果确实需要捕获禁用元素上的点击事件)的最简单、最清晰的方法就是将以下CSS添加到您的页面中:

input[disabled] {pointer-events:none}

这将使禁用输入框上的任何点击事件穿透到父元素,您可以在那里正常捕获它们。如果您有多个禁用的输入框,如果它们没有以这种方式布局,您可能需要将每个输入框放入自己的单独容器中,例如额外的<span><div>,以便轻松区分哪个禁用的输入框被点击了。


不幸的是,这个技巧在不支持pointer-events CSS属性的旧浏览器中不起作用。 (它应该从IE 11、FF v3.6、Chrome v4开始运行):caniuse.com/#search=pointer-events

如果您需要支持旧浏览器,您将需要使用其他答案之一!


我不确定 input[disabled] 是否也会匹配通过 JavaScript (element.disabled = true;) 禁用的元素,但它似乎确实如此。无论如何,我认为 input:disabled 更加简洁。 - Martin
这似乎是一个不错的解决方案,但在IE11中对我无效!另外,您说FF 38+和Chrome 31+,但您的caniuse链接说FF 3.6+和Chrome 4+? - user764754
@Martin:input:disabled是Jquery选择器,不能在CSS中使用,而input[disabled]可以。 - Protector one
3
@Protectorone :disabled 是CSS 3中的伪类选择器: https://www.w3.org/TR/css3-selectors/#UIstates - Martin
1
你是个天才!非常感谢你! - Luca Corsini
显示剩余3条评论

83

也许你可以将该字段设置为只读,在提交时禁用所有只读字段。

$(".myform").submit(function(e) {
  $("input[readonly]").prop("disabled", true);
});

输入(+脚本)应该是这样的

<input type="text" readonly="readonly" name="test" value="test" />

$('input[readonly]').click(function () {
  $(this).removeAttr('readonly');
});

一个实时例子:

$(".myform").submit(function(e) {
  $("input[readonly]").prop("disabled", true);
  e.preventDefault();
});


$('.reset').click(function () {
  $("input[readonly]").prop("disabled", false);
})

$('input[readonly]').click(function () {
  $(this).removeAttr('readonly');
})
input[readonly] {
  color: gray;
  border-color: currentColor;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form class="myform">
  <input readonly="readonly" value="test" />
  <input readonly="readonly" value="test" />
  <input readonly="readonly" value="test" />
  <input readonly="readonly" value="test" />
  <input readonly="readonly" value="test" />
  <input readonly="readonly" value="test" />
  <input readonly="readonly" value="test" />
  <input readonly="readonly" value="test" />
  <input readonly="readonly" value="test" />
  
  <button>Submit</button>
  <button class="reset" type="button">Reset</button>
</form>


6
+1,这是一个不错的备选建议。唯一的缺点是输入框无法采用禁用样式,不同浏览器之间的差异很大,因此很难使其看起来与用户对禁用输入的期望一致。 - Andy E
也许可以通过CSS解决这个问题?但是它看起来不会像普通的禁用输入字段那样。 - Tokimon
优秀的替代方案。我更喜欢这个,因为你可以使用CSS来进行必要的样式设计(比如让它看起来像被禁用了),但仍然保持事件可用。 - Joshua
这正是我所需要的! - Lorenzo

16

我建议使用另一种方法 - 使用CSS:

input.disabled {
    user-select : none;
    -moz-user-select : none;
    -webkit-user-select : none;
    color: gray;
    cursor: pointer;
}

可以使用 readonly 属性代替 disabled 属性。然后,您可以添加自己的 CSS 属性来模拟禁用输入框,但具有更多控制权。


4
仅支持IE10,太多用户使用IE9 / 8,因此不是一个可靠的替代方案。 - encodes
这仍然会导致在提交表单时发布该字段,在许多情况下这是不可取的。 - cimmanon

7

与其使用disabled,您可以考虑使用readonly。通过一些额外的CSS,您可以将输入框样式设置为看起来像一个disabled字段。

实际上还有另一个问题。事件change只有在元素失去焦点时才触发,这对于disabled字段来说是不合逻辑的。可能您正在从另一个调用中向该字段推送数据。要使此功能正常工作,您可以使用事件“bind”。

$('form').bind('change', 'input', function () {
    console.log('Do your thing.');
});

如果我没有弄错的话,只读输入字段仍将随表单提交。 - Pierre de LESPINAY
没错。然后应该与@npth的答案结合起来。 - Nykac
谢谢,这对我的情况来说非常聪明、干净和优化。 - Sultanos

7

$(function() {

  $("input:disabled").closest("div").click(function() {
    $(this).find("input:disabled").attr("disabled", false).focus();
  });

});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>

<div>
  <input type="text" disabled />
</div>


6
但是这在火狐浏览器上不起作用 - 这正是重点所在! - GarethOwen

4
使用jQuery和CSS也可以实现这个效果!
$('input.disabled').attr('ignore','true').css({
    'pointer-events':'none',
     'color': 'gray'
});

这样可以让元素看起来被禁用,不会触发任何指针事件,但它允许传播,如果提交了,您可以使用属性“ignore”来忽略它。

@Precastic,没错,但目前几乎所有其他浏览器都可以使用,并且您可以使用ie <11的polyfill。sidonaldson,为什么不使用纯CSS来应用样式呢? - KyleMit
@KyleMit,你可以添加一个类而不是设置样式,但这不是这个主题讨论的重点!我只是建议使用指针事件,这仍然是一个好的和正确的答案,具体取决于您正在构建的浏览器矩阵。 感谢所有将此答案标记为错误的人:/ - sidonaldson
1
@sidonaldson,这是一个很好的答案,我也希望它能排名更高。我不确定“ignore”属性的作用是什么。但是我的观点是,我认为我们不需要使用jQuery来应用CSS。您可以设置一个CSS规则,以定位相同的选择器并禁用指针事件。在这个fiddle中,jQuery和CSS应该做同样的事情,但CSS的性能会更好。 - KyleMit
@KyleMit 哦,好的,假设表单已经提交,你需要以某种方式告诉后端忽略该字段,如果它包含一个值(因为我们正在欺骗禁用)。 - sidonaldson
我同意CSS可以更强大,因为你可以使用基于属性的选择器!请查看此演示,在其中我匹配了Chrome自己的禁用字段:http://jsfiddle.net/KyleMit/pxx8pk6v/ - sidonaldson

1

你完全可以使用 CSS 和 readonly 的组合来模拟 disabled 属性,没有任何理由不这样做:

Faux-Disabled: <input type="text" value="1" readonly="1" style="background-color:#F6F6F6;"><br>

Real-Disabled: <input type="text" disabled="true" value="1"></input>

注意:这不会像在<form>中使用disabled那样有常规行为,它可以防止服务器看到该字段。这只是为了在您想要禁用服务器端无关紧要的字段时使用。


0
今天我们遇到了这样的问题,但我们不想更改 HTML。因此,我们使用mouseenter事件来实现它。
var doThingsOnClick = function() {
    // your click function here
};

$(document).on({
    'mouseenter': function () {
        $(this).removeAttr('disabled').bind('click', doThingsOnClick);
    },
    'mouseleave': function () {
        $(this).unbind('click', doThingsOnClick).attr('disabled', 'disabled');
    },
}, 'input.disabled');

0

我做了与Andy E非常相似的事情; 除此之外,我使用了一个周围的<a>标签。然而,我需要“名称”,所以我将其更改为没有“href”的<a>标签。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接