如何通过单击取消选中单选按钮?

IT技术 javascript html radio-button
2021-02-20 01:16:15

与复选框不同,一旦单击单选按钮,用户就无法取消选择它们。有什么方法可以使用 Javascript 以编程方式切换它们吗?这最好不使用 jQuery。

6个回答

您可以HTML对象的属性设置checked,以false这样的:

document.getElementById('desiredInput').checked = false;

例子

Plain JavaScript

var radios = document.getElementsByTagName('input');
for(i=0; i<radios.length; i++ ) {
    radios[i].onclick = function(e) {
        if(e.ctrlKey || e.metaKey) {
            this.checked = false;
        }
    }
}
<input type="radio" name="test" value="1" />
<input type="radio" name="test" value="2" checked="checked" />
<input type="radio" name="test" value="3" />

jQuery

$('input').click(function(e){
    if (e.ctrlKey || e.metaKey) {
        $(this).prop('checked', false);
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="radio" name="test" value="1" />
<input type="radio" name="test" value="2" checked="checked" />
<input type="radio" name="test" value="3" />

按住Ctrl在 mac 上)键取消选中。

@pinkpanther,绝对不是。我认为这是这个问题的最大难点。删除if ctrlKey,然后……好吧,您可以取消选中它……但是您永远不能选中收音机,因为 [click] 事件目标的checked属性将始终显示为 checked
2021-05-02 01:16:15
这看起来就像我需要的那样,但是有什么方法可以不用按 Ctrl 来做到这一点?谢谢!
2021-05-06 01:16:15
@JohnSawatzky 当然,只需删除支票 if(e.ctrlKey) {...
2021-05-11 01:16:15
有没有办法说一个特定的单选按钮是否已经被选中/真,然后再次点击它,然后将它切换到取消选中/假,并使其成为文档中所有 type="radio" 元素的默认行为?我问是因为如果用户在平板电脑或触摸屏上,按住 CTRL 键不是很容易做到。
2021-05-13 01:16:15
@Teneff 没有办法让它检查
2021-05-14 01:16:15

单选按钮旨在按组使用,因为它们共享相同的name属性。然后单击其中之一取消选择当前选定的一个。要允许用户取消他所做的“真实”选择,您可以包含一个与空选择相对应的单选按钮,例如“不知道”或“没有答案”。

如果您想要一个可以选中或取消选中的按钮,请使用复选框。

可以(但通常不相关)取消选中 JavaScript 中的单选按钮,只需将其checked属性设置为 false,例如

<input type=radio name=foo id=foo value=var>
<input type=button value="Uncheck" onclick=
"document.getElementById('foo').checked = false">
晚了几年,但是......然后你建立一个。我已经足够频繁地构建该 UI - 您将它们设置为复选框,然后将一个事件绑定到它们,因此如果您选中“以上都不是”(或其他任何内容),它会取消选中其他的,如果您选中任何一个其他的,它取消选中那个。
2021-04-24 01:16:15
如果您想要多个按钮作为一个组同时保持未选中的选项(或至少一个的视觉外观)怎么办?您的解决方案忽略了最终用户并要求基本上重写现有代码......
2021-05-17 01:16:15

这是我的答案(虽然我是用 jQuery 制作的,但仅用于选择元素以及添加和删除类,因此您可以轻松地将其替换为纯 JS 选择器和纯 JS 添加属性)

<input type='radio' name='radioBtn'>
<input type='radio' name='radioBtn'>
<input type='radio' name='radioBtn'>

$(document).on("click", "input[name='radioBtn']", function(){
    thisRadio = $(this);
    if (thisRadio.hasClass("imChecked")) {
        thisRadio.removeClass("imChecked");
        thisRadio.prop('checked', false);
    } else { 
        thisRadio.prop('checked', true);
        thisRadio.addClass("imChecked");
    };
})
听着,在 2 个不同的点 + 框架 + 实现上花费 [大量] 时间解决这个问题后,这是 [可能] 唯一可行的答案使用clicks 根本不起作用,因为.checked它总是正确的;mousedown不起作用,因为mouseup它毁了它——即使有e.preventDefault();e.stop[Immediate]Propagation();; 下一个最好的技术是e.ctrlKey上面提到方法——但这需要用户的一些特殊知识。唯一的方法是 [可能] 使用某种 哨兵,例如 aclassdata-checked证明我错了,请!!!
2021-04-21 01:16:15
@Cody 接受了挑战,我在这里证明你错- 请参阅答案的底部。
2021-04-25 01:16:15
我花了大约三秒钟才想出相同的(概念上的)答案……做了一个小提琴来证明它有效……我确信纯 javascript 可以用来做同样的事情,只是不要想花时间去做... 工作示例
2021-05-03 01:16:15
这个对我有用。除了当我点击一个未选中的单选按钮来选择它时,我必须点击它两次才能被选中。第一次点击取消选中的那个,第二次点击我要检查的那个:)。
2021-05-08 01:16:15

取消选中收音机如何(不)工作

您无法通过if(this.checked) this.checked = false,轻松实现取消选中(如果您真的想要,请参阅最后的黑客方式),因为事件按以下顺序触发:

  1. mousedown 或者 keydown
  2. mouseup 或者 keyup
  3. 如果未选中,请立即设置选中的属性
  4. click
  5. input (仅当状态改变时)
  6. change (仅当状态改变时)

现在在哪个事件中执行提到的取消选中?

  • mouseupmousedown:然后在第 3 步中将值设置回 true 并且更改和输入事件甚至不会触发,因为在序列中调用它们时状态没有更改 - 所以你不能在这里取消选中它
  • click:那么状态总是假的,输入和更改也不会触发 - 所以你不能检查它
  • input或者change:当状态没有改变并且点击所选元素不会改变状态时它不会触发 - 所以你不能在这里做任何有用的事情

天真的方式

从上面的序列可以看出,方法是:

  1. 读取之前的状态 mouseup
  2. 将状态设置click为先前状态的否定

如果你想在 data 属性中存储之前的状态,记住它被保存为string,而被检查的属性是boolean所以你可以像这样实现它:

radio.onmouseup = function() { this.dataset.checked = this.checked? 1 : ""; }
radio.onclick = function() { this.checked = !this.dataset.checked; }

它似乎有效,但由于以下原因,您不应该这样做:

  • 用户可能会在mousedown其他地方,然后将鼠标悬停在单选按钮上方,然后mouseup:在这种情况下,mouseup 会触发,而 click 不会
  • 用户可以使用Tab聚焦无线电组,然后arrows更改:mouseup 不会触发,而 click 会

正确的方法

还有另一个问题:动态添加的单选按钮。有两种方式:

  1. element.appendChild(radio)- 如果您在DOMContentLoaded事件中对所有无线电启用取消选择,则此动态添加的无线电不受影响
  2. element.innerHTML+= '<input type="radio">' - 有效地替换元素的 HTML 内容并在其中重新创建 DOM - 因此所有事件侦听器都被丢弃

为了解决(2),我推荐onclick 内容属性请注意,element.onclick = fnelement.setAttribute("onclick", "fn()")是两个不同的东西。另请注意,onclick每次用户激活无线电时都会触发,无论他使用什么接口。

另一个问题:如果您启用取消选择,那么您还应该启用切换Space以模仿复选框行为。以下代码解决了所有提到的问题:

function deselectableRadios(rootElement) {
  if(!rootElement) rootElement = document;
  if(!window.radioChecked) window.radioChecked = {};
  window.radioClick = function(e) {
    const obj = e.target, name = obj.name || "unnamed";
    if(e.keyCode) return obj.checked = e.keyCode!=32;
    obj.checked = window.radioChecked[name] != obj;
    window.radioChecked[name] = obj.checked ? obj : null;
  }
  rootElement.querySelectorAll("input[type='radio']").forEach( radio => {
    radio.setAttribute("onclick", "radioClick(event)");
    radio.setAttribute("onkeyup", "radioClick(event)");
  });
}

deselectableRadios();
<label><input type="radio" name="tag1">one</label>
<label><input type="radio" name="tag1">two</label>
<label><input type="radio" name="tag1">three</label>

<br><br>

<label><input type="radio" name="tag2">one</label>
<label><input type="radio" name="tag2">two</label>
<label><input type="radio" name="tag2">three</label>

现在,您可以deselectableRadios()随时动态添加内容并在收音机上多次调用它并不会破坏它。您还可以指定rootElement仅更新 HTML DOM 的子树并使您的网络更快。如果不喜欢全局状态,可以使用hacker方式:

黑客之道

重点是在设置好checked属性后滥用setTimeoutonmouseup调用它:

function deselectable() {
  setTimeout(checked => this.checked = !checked, 0, this.checked);
}

现在您可以取消选择任何单选按钮:

radio.onmouseup = deselectable;

但是这个简单的单行只需要点击就可以工作,并不能解决上面提到的问题。

被遗弃的未来

可取消选择的收音机基本上是一个复选框,其中只能选中组中的一个。有一个有希望的直接希望将其编码为

<input type="checkbox" name="foo" style="appearance: radio">

但是,该radio值现在被定义为compat-auto类型,它被视为auto,即没有视觉变化。看来以后这里不会有什么进展了。

@zed 很好,伙计,谢谢。它通过对两个单选按钮组的测试得到修复和更新。
2021-04-28 01:16:15
@JanTuroň,看起来“正确的方式”有一个小错误,如果您有多个收音机组,并且您在第一组中选择一个选项,然后单击第二组中的一个选项,然后返回再次单击第一组上的选定选项,它不会被取消选择(您需要单击它两次以使其取消选择)。
2021-04-29 01:16:15
谢谢@JanTuroň!现在它就像一个魅力。我将它与 3 个单选按钮组一起使用。
2021-05-14 01:16:15

包裹在一个插件中

限制:

  1. 需要表单元素
  2. 以编程方式更改单选按钮时必须触发单击事件

(function($) {
  $.fn.uncheckableRadio = function() {
    var $root = this;
    $root.each(function() {
      var $radio = $(this);
      if ($radio.prop('checked')) {
        $radio.data('checked', true);
      } else {
        $radio.data('checked', false);
      }
        
      $radio.click(function() {
        var $this = $(this);
        if ($this.data('checked')) {
          $this.prop('checked', false);
          $this.data('checked', false);
          $this.trigger('change');
        } else {
          $this.data('checked', true);
          $this.closest('form').find('[name="' + $this.prop('name') + '"]').not($this).data('checked', false);
        }
      });
    });
    return $root;
  };
}(jQuery));

$('[type=radio]').uncheckableRadio();
$('button').click(function() {
  $('[value=V2]').prop('checked', true).trigger('change').trigger('click');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<form>
  <label><input name="myRadio" type="radio" value="V1" /> R1</label>
  <label><input name="myRadio" type="radio" value="V2" /> R2</label>
  <label><input name="myRadio" type="radio" value="V3" /> R3</label>
  <button type="button">Change R2</button>
</form>

很好,很好用。我们可以使用随机标记代替<form>封装单选按钮,只需在此处更改:$this.closest('form')
2021-04-22 01:16:15