与复选框不同,一旦单击单选按钮,用户就无法取消选择它们。有什么方法可以使用 Javascript 以编程方式切换它们吗?这最好不使用 jQuery。
如何通过单击取消选中单选按钮?
您可以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 上)键取消选中。
单选按钮旨在按组使用,因为它们共享相同的name
属性。然后单击其中之一取消选择当前选定的一个。要允许用户取消他所做的“真实”选择,您可以包含一个与空选择相对应的单选按钮,例如“不知道”或“没有答案”。
如果您想要一个可以选中或取消选中的按钮,请使用复选框。
可以(但通常不相关)取消选中 JavaScript 中的单选按钮,只需将其checked
属性设置为 false,例如
<input type=radio name=foo id=foo value=var>
<input type=button value="Uncheck" onclick=
"document.getElementById('foo').checked = false">
这是我的答案(虽然我是用 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");
};
})
取消选中收音机如何(不)工作
您无法通过if(this.checked) this.checked = false
,轻松实现取消选中(如果您真的想要,请参阅最后的黑客方式),因为事件按以下顺序触发:
mousedown
或者keydown
mouseup
或者keyup
- 如果未选中,请立即设置选中的属性
click
input
(仅当状态改变时)change
(仅当状态改变时)
现在在哪个事件中执行提到的取消选中?
mouseup
或mousedown
:然后在第 3 步中将值设置回 true 并且更改和输入事件甚至不会触发,因为在序列中调用它们时状态没有更改 - 所以你不能在这里取消选中它click
:那么状态总是假的,输入和更改也不会触发 - 所以你不能检查它input
或者change
:当状态没有改变并且点击所选元素不会改变状态时它不会触发 - 所以你不能在这里做任何有用的事情
天真的方式
从上面的序列可以看出,方法是:
- 读取之前的状态
mouseup
- 将状态设置
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 会
正确的方法
还有另一个问题:动态添加的单选按钮。有两种方式:
element.appendChild(radio)
- 如果您在DOMContentLoaded
事件中对所有无线电启用取消选择,则此动态添加的无线电不受影响element.innerHTML+= '<input type="radio">'
- 有效地替换元素的 HTML 内容并在其中重新创建 DOM - 因此所有事件侦听器都被丢弃
为了解决(2),我推荐onclick 内容属性。请注意,element.onclick = fn
和element.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属性后滥用setTimeout
onmouseup
调用它:
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
,即没有视觉变化。看来以后这里不会有什么进展了。
包裹在一个插件中
限制:
- 需要表单元素
- 以编程方式更改单选按钮时必须触发单击事件
(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>