如何在点击时选中/取消选中单选按钮?

How to check/uncheck radio button on click?

提问人:Richard Knop 提问时间:2/10/2011 更新时间:11/13/2022 访问量:117732

问:

我希望能够通过单击取消选中单选按钮。

因此,如果取消选中单选按钮,我想检查它,如果选中,我想取消选中它。

这不起作用:

$('input[type=radio]:checked').click(function(){
    $(this).attr('checked', false);
});

我现在无法检查单选按钮。

JavaScript jQuery

评论

0赞 Mahesh Velaga 2/10/2011
您的意思是选择/取消选择而不是检查/取消选中吗?

答:

1赞 Daric 2/10/2011 #1

如果只有一个单选按钮,则需要改用复选框。

拥有一个单选按钮是没有意义的,他们与组一起工作。

可能您正在寻找复选框控件。

评论

10赞 Richard Knop 2/10/2011
组中有更多的单选按钮。将它们全部取消选中是有效的,因此我想允许用户取消选中它们。
22赞 Stephen 2/10/2011 #2

试试这个:

$('input[type=radio]').click(function(){
    if (this.previous) {
        this.checked = false;
    }
    this.previous = this.checked;
});

评论

9赞 Sparky 10/18/2011
由于@HexInteractive回答中所述的原因,您的解决方案效果不佳。我在 Webkit 中,它表现得非常不稳定......是的,它允许取消选择单选按钮,但大多数情况下,您必须单击两次单选按钮才能选择它们。jsfiddle.net/sparky672/KdZG7
0赞 Christian Michael 9/26/2017
在 chrome 和现在它工作。还有其他人可以证实或反驳这一点吗?
0赞 Kevin 8/13/2018
在 Chrome 版本 68 中顺利运行(截至 2018 年 8 月)。
1赞 Daniel Rodríguez 8/8/2019
在 firefox 中也适用于 v68
1赞 Anjan Biswas 9/1/2021
有时需要单击两次才能取消选中前一次。
82赞 HexInteractive 6/6/2011 #3

这不是要替换复选框,而是要允许单选组返回到未选择的状态。这很棘手,因为无线电选择不像正常事件。

浏览器处理正常事件链之外的单选按钮。因此,带有 event.preventDefault() 或 event.stopPropagation() 的单选按钮上的单击处理程序不会阻止单选按钮被检查。必须在 setTimeout 中完成 .removeAttr('checked') 以允许事件完成,并且浏览器(再次)检查单选按钮,然后 setTimeout 将触发。

这也可以正确处理用户启动鼠标按下但在鼠标升起之前离开单选按钮的情况。

//$ = jQuery;
$(':radio').mousedown(function(e){
  var $self = $(this);
  if( $self.is(':checked') ){
    var uncheck = function(){
      setTimeout(function(){$self.removeAttr('checked');},0);
    };
    var unbind = function(){
      $self.unbind('mouseup',up);
    };
    var up = function(){
      uncheck();
      unbind();
    };
    $self.bind('mouseup',up);
    $self.one('mouseout', unbind);
  }
});

我希望这会有所帮助

评论

1赞 Anderson Pimentel 7/27/2012
这简直让我发疯了!谢谢!
0赞 user1900121 10/16/2013
它确实在 Firefox 18 上工作,伙计!(同意天才一词!
1赞 oneberenjena 10/9/2019
只是要指出,今天这仍然是一个很好的解决方案。另外,可以替换为 和 to 以摆脱已弃用的方法。最后,我使用标签方法实现了这一点,以防万一有人想知道在这种情况下这是否也有助于:)$self.bind('mouseup', up)$self.mouseup(up)$self.unbind('mouseup',up)$self.off('mouseup')
0赞 Harshal Parekh 4/9/2020
未来的读者,在盲目复制此解决方案之前,请阅读此答案(stackoverflow.com/a/27476660/8430155)。
0赞 Haskell McRavin 3/19/2021
不知道为什么要依靠 mouseout 来解绑鼠标。这工作正常。$self.one('mouseup', up);
4赞 James Barnsley 1/16/2012 #4

这才是真正的解决方案......

var check;

$('input[type="radio"]').hover(function() {
    check = $(this).is(':checked');
});

$('input[type="radio"]').click(function() {
    check = !check;
    $(this).attr("checked", check);
});

试试吧,它对我有用!

评论

0赞 Ben 4/24/2014
我不得不稍微调整一下,以便在我的情况下工作,我希望通过单击父项来选择/取消选择单选按钮。但我所要做的就是将第一个更改为和更改为div$('input[type="radio"]')$('div.parentClass')check = $(this).is(':checked');check = $(this).find('input[type="radio"]').is(':checked');
0赞 karaxuna 11/19/2012 #5
 var checked = {};
    $('.desectable-radio').each(function (index) {
        checked[index] = this.checked;
        $(this).click(function () {
            if (checked[index])
                this.checked = false;
            for (var i in checked) {
                checked[i] = false;
            }
            checked[index] = this.checked;
        });
    });
2赞 Tony Hayes 1/10/2013 #6

在寻找解决方案时在某个地方找到了这个,喜欢它的简单性......

var checkedradio;
function docheck(thisradio) {
    if (checkedradio == thisradio) {
        thisradio.checked = false;
        checkedradio = null;
    }
    else {checkedradio = thisradio;}
}

与以下设备一起使用:

<input type='radio' onclick='docheck(this);'>

不过,当您在一个表单中有多个单选按钮组时,似乎确实需要双击才能取消选择,但这可以通过为每个组设置一个功能来解决......

评论

0赞 Friedrich -- Слава Україні 11/6/2022
谢谢,确实,没有双击!代码高尔夫: .这一个班轮也可以做到。checkedradio = (thisradio.checked &= checkedradio != thisradio) && thisradio
1赞 Eterm 1/10/2013 #7

UX 最好有一个默认选择的“不选择”显式选项,并且不要让用户取消选中任何单选按钮。

(此nngroup(neilsen)文章中的列表项9:

http://www.nngroup.com/articles/checkboxes-vs-radio-buttons/

评论

2赞 MemeDeveloper 9/13/2013
这是有待商榷的,有很多很多不同的用例,所以尼尔森的概括就是这样......即概括。
0赞 KyleMit 6/30/2014 #8

下面是一个超轻量级脚本,您可以通过控制台窗口将其添加到页面中,该脚本允许您通过按住单选按钮并单击鼠标来取消选择该单选按钮。Ctrl

document.addEventListener('click', function(e){
   if (e.ctrlKey == true && 
       e.target.tagName == 'INPUT' && 
       e.target.type == "radio" && 
       e.target.checked == true) {
       e.target.checked = false;
   }
});

由于它不依赖于 jQuery,因此您可以轻松地将其添加到任何页面以暂时允许取消选择。
有关更多信息,您可以阅读我刚刚写的一篇关于如何取消选择单选按钮的文章。

15赞 Jase in ATL 12/15/2014 #9

接受的答案不适用于移动设备。它依赖于 setTimeout 和绑定,这些绑定与鼠标事件相关,这些事件不会在平板电脑/移动设备上触发。
我的解决方案是使用“click”事件处理程序和自定义类状态手动跟踪所选状态。

  1. 处理无线电输入元素上的单击事件
  2. 检查单击的元素上是否存在“Selected”类
  3. 如果是这样,(意味着它之前已被单击过),则删除该类并取消选中该元素,返回
  4. 如果没有,请从同名的所有元素中删除该类,并将其仅添加到单击的元素中。

无需阻止默认行为。下面是 Jquery 中的代码:

$("input:radio").on("click",function (e) {
    var inp=$(this); //cache the selector
    if (inp.is(".theone")) { //see if it has the selected class
        inp.prop("checked",false).removeClass("theone");
        return;
    }
    $("input:radio[name='"+inp.prop("name")+"'].theone").removeClass("theone");
    inp.addClass("theone");
});

http://jsfiddle.net/bhzako65/

评论

0赞 Rafael 9/1/2016
有趣的是,我正在努力理解为什么添加类会删除选定的状态:o)
0赞 Armen Michaeli 11/2/2017
自定义类与按钮状态无关。您可以随心所欲地设置其样式,但检查状态与类无关。
2赞 ArkTekniK 6/17/2016 #10

我知道这个问题很老了,但我刚刚遇到这个问题并决定自己试一试,不想使用像 ctrl 这样的修饰键按钮。

http://jsfiddle.net/ArktekniK/yhbw469f/ 上看到小提琴 通过单击单选按钮本身来切换单选按钮

$('input[type=radio]').on('mousedown', function(e){
  var wasChecked = $(this).prop('checked');
  this.turnOff = wasChecked;
  $(this).prop('checked', !wasChecked);
});

$('input[type=radio]').on('click', function(e){
  $(this).prop('checked', !this.turnOff);
  this['turning-off'] = !this.turnOff;
});

通过单击标签或单选按钮本身来切换单选按钮

$('label:has(input[type=radio])').on('mousedown', function(e){
  var radio = $(this).find('input[type=radio]');
  var wasChecked = radio.prop('checked');
  radio[0].turnOff = wasChecked;
  radio.prop('checked', !wasChecked);
});

$('label:has(input[type=radio])').on('click', function(e){
  var radio = $(this).find('input[type=radio]');
  radio.prop('checked', !radio[0].turnOff);
  radio[0]['turning-off'] = !radio[0].turnOff;
});

评论

0赞 Rafael 9/1/2016
这个问题很老了,但有新的用途。谢谢。
0赞 Rafael 9/3/2016
哦。由于某种原因,当您使用标签时,这不起作用:jsfiddle.net/1bfsnzn9/5
0赞 ArkTekniK 9/3/2016
@Rafael你的链接似乎对我来说很好用。我可以切换收音机。我在 Windows 53.0.2785.89 上使用 Chrome 10。我假设您的意思是单击标签本身而不是单选按钮不会触发切换行为?
0赞 ArkTekniK 9/3/2016
@Rafael试试这个:jsfiddle.net/ArktekniK/1bfsnzn9/6 我会把它添加到答案中
1赞 kay 7/12/2016 #11

正如 HexInteractive 所提到的,单选按钮是在正常事件链之外处理的。 因此,以下示例通过类名而不是属性来判断按钮状态。

var $self;

$('input[type=radio]').on('click', function() {
  $self = $(this);
  if ( $self.hasClass('is-checked') ) {
    $self.prop('checked', false).removeClass('is-checked');
  } else {
    $self.addClass('is-checked');
  }
});
0赞 Matt Saunders 8/31/2017 #12

需要解决这个问题,我决定用“取消”图标按钮替换当前活动的单选按钮,如下所示 http://fontawesome.io/icon/ban/

单击此图标取消选中活动单选按钮,该按钮随后重新出现,有效地重置单选按钮组。取消图标也已从 DOM 中删除。

或者,用户可以单击组中的另一个单选按钮,除了取消按钮外,该按钮将正常运行,然后“移动”该按钮以替换新的活动单选按钮。

这样可以将取消图标保持在直观的位置(即用户上次单击的位置),并且比假设用户知道重新单击当前活动的单选按钮以停用组更安全。

最坏的情况是,如果您有一长串单选按钮,用户只需单击其中任何一个按钮两次即可清除该组。

评论

0赞 Arun Vinoth-Precog Tech - MVP 8/31/2017
如果您有其他问题,请单独提出。如果上下文会有所帮助,您可以链接这个问题。但这并不试图回答OP问题。
0赞 BSMP 8/31/2017
@ArunVinoth Matt 描述的是他们使用的解决方法,而不是提出新问题。如果它们包含演示所描述行为的代码会更好,但这是一个“这样做是为了获得您想要的功能”类型的答案。
0赞 Matt Saunders 9/1/2017
是的 - 我是根据 @Eterm 的建议构建的,即从 UI 的角度来看,“取消”按钮比第二次单击选定的单选按钮更直观,并补充说最好的位置是代替活动单选按钮。我将编写一些代码并将其添加进去。
2赞 Eugeny K 4/5/2019 #13

谁正在寻找纯 JavaScript 解决方案,我在 ATL 的回答中修改了 Jase 的代码。

我编写此代码是为了建议与 CSS 样式的 3 位开关一起使用,该开关提供 4 种切换状态(开、关、中性和未激活)。

function toggle_radio(ev) {
	var radio = ev.target;
	var cut_pos = radio.className.indexOf(' switcher-active');

	// the switch itself
	if (cut_pos !== -1) { // if the button checked it is '.switcher-active'
		radio.checked = false; // toggle its state
		radio.className = radio.className.slice(0, cut_pos); // remove '.switcher-active'
		return true; // work is done. Break the function
	}

	// the button was inactive before it was clicked. Then it should became '.switcher-active'
	radio.className = radio.className + ' switcher-active';

	// we need to remove '.switcher-active' if either the left or right radio button was clicked. This part is uggly but I don't bother, because I'm late for barber
	var radios = document.getElementsByName(radio.name); // get all these radio siblings as a collection of elements
	for (var i=0; i < radios.length; i++) { // iterate through the collection
		if (radios[i].className.indexOf('switcher-radio-neutral') !== -1)
			continue; // skip the '.switcher-neutral' radio input

		radios[i].onclick = function(ev2) {
			sib_radios = document.getElementsByName(ev2.target.name); // get a group of radio inputs linked by the name

			// get the '.switcher-neutral'
			for (var k=0, cut_pos = -1, sib; k < sib_radios.length; k++) {
				sib = sib_radios[k];
				cut_pos = sib.className.indexOf(' switcher-active');
				if (cut_pos !== -1)
					sib.className = sib.className.slice(0, cut_pos);
			}
		}
	}
}

var switchers = document.getElementsByClassName('switcher-radio-neutral');

for (var i=0; i < switchers.length; i++) { // bind onclick handlers
	switchers[i].onclick = toggle_radio;
}
.switcher {
	position: relative;
	display: inline-block;
	margin: 1px 10px;
	height: 20px;
	width: 58px;
	z-index: 1;
}

.switcher-off {
	left: 1px;
	width: 33%;
	height: 100%;
}

.switcher-neutral {
	left: 33%;
	width: 33%;
	height: 100%;
}

.switcher-on{
	right: 1px;
	width: 33%;
	height: 100%;
}

.switcher-label {
	position: absolute;
	text-indent: -9999px;
	z-index: 2;
}

.switcher input {
	visibility: hidden;
	position: absolute;
}

.switcher-slider {
	height: 100%;
	width: 100%;
	border-radius: 10px;
	box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1) inset, 0 0 4px rgba(0, 0, 0, 0.5) inset, 0 2px 2px 1px rgba(0, 0, 0, 0.3) inset;
	transition: background-color 0.2s linear 0s;
}

.switcher-slider:after {
	transition: left 0.2s linear 0s, right 0.2s linear 0s;
	background: linear-gradient(#D0D0D0, #FDFDFD) repeat scroll 0 0 rgba(0, 0, 0, 0);
	content: "";
	position: absolute;
	top: 1px;
	border-radius: 50%;
	height: calc(100% - 2px);
	width: calc(100%/3 - 1px);
	box-shadow: 0 0 1px 1px #f4f4f4 inset, 0 0 3px 1px rgba(0, 0, 0, 0.6);
	left: 33%;
}

.switcher-radio-on:checked  ~ .switcher-slider {
	background-color: #81EA89;
}

.switcher-radio-neutral:checked  ~ .switcher-slider {
	background: #ddd;
}

.switcher-radio-off:checked  ~ .switcher-slider {
	background-color: #ED8282;
}

.switcher-radio-on:checked  ~ .switcher-slider:after {
	left: calc(2*(100%/3));
}

.switcher-radio-neutral:checked  ~ .switcher-slider:after {
	left: calc(1px + 100%/3);
}

.switcher-radio-off:checked  ~ .switcher-slider:after {
	left: 1px;
}
<form action="">
		<input type="radio" name="radio_input" value="1">
		<input type="radio" name="radio_input" class="switcher-radio-neutral" value="2">
		<input type="radio" name="radio_input" value="3">
</form>
<br><br>
<div class="switcher">
	<label  class='switcher-label switcher-off' for='off'>off</label>
	<input id='off' class='switcher-radio-off' type='radio' name='value' value='off'>
	
	<label class='switcher-label switcher-neutral' for='neutral'>neutral</label>
	<input id='neutral' class='switcher-radio-neutral' type='radio' name='value' value='neutral' data-neutral="">
	
	<label class='switcher-label switcher-on' for='on'>on</label>
	<input id='on' class='switcher-radio-on' type='radio' name='value' value='on'>
	<div class='switcher-slider'></div>
</div>

6赞 gman 6/20/2019 #14

我一定很想念它,但经过这么多年,AFAIK 上述解决方案似乎都不起作用,或者我只是愚蠢。

绝对没有理由使用单选按钮,除非同一组中有多个单选按钮。如果它是一个单独的单选按钮,那么只需使用一个复选框。使用单选按钮的原因是为了选择互斥选项之一。这意味着任何只查看单个按钮的解决方案都将失败,因为单击一个按钮将影响其他按钮的状态

换句话说,由于我们使用的是单发盒,因此该解决方案需要工作

<input type="radio" name="foo" id="foo1"><label for="foo1">foo1</label>
<input type="radio" name="foo" id="foo2"><label for="foo2">foo2</label>
<input type="radio" name="foo" id="foo3"><label for="foo3">foo3</label>

这是一个查看所有按钮的按钮。

这似乎有效

document.querySelectorAll(
    'input[type=radio][name=foo]').forEach((elem) => {
  elem.addEventListener('click', allowUncheck);
  // only needed if elem can be pre-checked
  elem.previous = elem.checked;
});

function allowUncheck(e) {
  if (this.previous) {
    this.checked = false;
  }
  // need to update previous on all elements of this group
  // (either that or store the id of the checked element)
  document.querySelectorAll(
      `input[type=radio][name=${this.name}]`).forEach((elem) => {
    elem.previous = elem.checked;
  });
}
body { font-size: xx-large; }
label, input {
  /* added because a second click to unselect radio often
     appears as a double click to select text */
  -webkit-user-select: none;
  user-select: none;
}
<input type="radio" name="foo" id="foo1"><label for="foo1">foo1</label>
<input type="radio" name="foo" id="foo2"><label for="foo2">foo2</label>
<input type="radio" name="foo" id="foo3"><label for="foo3">foo3</label>

注意:如果担心你,你可以使用elem.previouselem.dataset.previous

另一种解决方案是存储选中的按钮

function makeRadioboxGroupUnCheckable(groupSelector) {

  let currentId;

  document.querySelectorAll(groupSelector).forEach((elem) => {
    elem.addEventListener('click', allowUncheck);
    // only needed if can be pre-checked
    if (elem.checked) {
      currentId = elem.id;
    }
  });

  function allowUncheck(e) {
    if (this.id === currentId) {
      this.checked = false;
      currentId = undefined;
    } else {
      currentId = this.id;
    }
  }
}

makeRadioboxGroupUnCheckable('input[type=radio][name=foo]');
body { font-size: xx-large; }
label, input {
  /* added because a second click to unselect radio often
     appears as a double click to select text */
  -webkit-user-select: none;
  user-select: none;
}
<input type="radio" name="foo" id="foo1"><label for="foo1">foo1</label>
<input type="radio" name="foo" id="foo2"><label for="foo2">foo2</label>
<input type="radio" name="foo" id="foo3"><label for="foo3">foo3</label>

1赞 Jammers1978 1/31/2020 #15

根据 Stephen 的回答 - 这涉及多个单选按钮组,而且您大多不需要双击单选按钮。它并不完美,因为如果您在组之间切换,检查 id 将需要额外的点击,但工作正常。

$("input[type='radio']").on('click', function (e) {
            if (this.previous && this.value == previousvalue && this.id == previousid) {
                this.checked = false;
            }
            this.previous = this.checked;
            previousvalue = this.value;
            previousid = this.id;

        });
0赞 GrayGalaxy 8/1/2020 #16

我认为这是最短的路。我在 Chrome 和 MS Edge 上测试了它。

$(document).on('click', 'input:radio', function () {
    var check = $(this).attr('checked')
    if (check) $(this).removeAttr('checked').prop('checked',false)
    else $(this).attr('checked', true).prop('checked',true)
})

这段代码也适用于 AJAX 加载的内容

0赞 devdrc 9/18/2020 #17

使用带有 checked 作为键的 prop 函数:

$("input:radio").prop("checked",false);
1赞 Aashir Azeem 10/29/2020 #18

是的,您也可以在单击选中时执行此操作,再次单击取消选中。 这是其中的逻辑:

$('input[name=check1]').prop('checked',!$('input[name=check1]').prop('checked'));
0赞 Haskell McRavin 3/19/2021 #19

这应该适用于桌面和移动设备。我在 Chrome 和 Firefox 上进行了测试。 基于评分最高的答案,但使用更新的 JQuery 和使用 $.one 的更简单的实现。

$(':radio').on("mousedown touchstart", function (e) {
    var mobile = true;
    if(e.type.toLowerCase() === 'mousedown'){
        mobile = false;
    }
    
    var $self = $(this);
    if($self.prop('checked')){
        var uncheck = function(){
            setTimeout(function(){
                $self.prop('checked',false);
            },10);
        };
        if(!mobile){
            $self.one('mouseup', uncheck);
        } else {
            $self.one('touchstart', uncheck);
        }
    }
});
0赞 Emrul Hasan piam 7/6/2021 #20
<script type="text/javascript">
    $( document ).ready(function() {
        $('input[type=radio]').click(function(){
            if (this.previous) {
                this.checked = false;
                document.getElementById("nc").style.display = "block";
                this.previous=false;
            }
            else {
                this.previous = this.checked;
                document.getElementById("nc").style.display = "none";
            }
        });
    });
</script>
1赞 Friedrich -- Слава Україні 11/6/2022 #21

一个纯CSS解决方案(没有javascript)

label > input:checked,
label > input:checked + label {
    pointer-events: none;
}

#unselect {
    display: none;   
}
<input type="radio" name="foo" id="unselect">
<label for="unselect">
  <input type="radio" name="foo" id="foo1">
  <label for="foo1">foo1</label>
  <input type="radio" name="foo" id="foo2">
  <label for="foo2">foo2</label>
  <input type="radio" name="foo" id="foo3">
  <label for="foo3">foo3</label>
</label>

单选按钮嵌入到另一个单选按钮中。 选择单选按钮后,它不再接受单击,而是基础单选按钮捕获单击。

https://jsfiddle.net/w29rem7q/

原始的、现已过时的解决方案

每个单选按钮都附加了一个虚拟单选按钮。如果选择了单选按钮,则单选按钮上方将出现一个不可见的虚拟人,以捕捉下一次单击。

input:not([id^=foo]) {
  opacity: 0.0;
}
input[id^=foo]:checked {
  position: absolute;
}
input[id^=foo]:not(:checked) + input {
  display: none;
}
<input type="radio" name="foo" id="foo1">
<input type="radio" name="foo">
<label for="foo1">foo1</label>
<input type="radio" name="foo" id="foo2">
<input type="radio" name="foo">
<label for="foo2">foo2</label>
<input type="radio" name="foo" id="foo3">
<input type="radio" name="foo">
<label for="foo3">foo3</label>

可能只是为了好玩,而在实践中,js 会更容易维护。
此外,通过标签单击取消选择,将有更多的解决方法。

0赞 Friedrich -- Слава Україні 11/6/2022 #22

一个 javascript 版本,具有通过 和 无需双击取消选择的功能。
临时状态附加到父 div。
forlabel

Parent.onclick = e => {
  rb = e.target;
  if (rb.type == "radio") {
    if (Parent.rb == rb) {
      rb.checked = false;
      Parent.rb = null;
    } else {
      Parent.rb = rb
    }
  }
}
<div id="Parent">
  <input type="radio" name="foo" id="foo1">
  <label for="foo1">foo1</label>
  <input type="radio" name="foo" id="foo2">
  <label for="foo2">foo2</label>
  <input type="radio" name="foo" id="foo3">
  <label for="foo3">foo3</label>
</div>