简体   繁体   English

单击其他按钮后取消选中单选按钮

[英]Unchecking a radio button after clicking a different one

I'm making a voting system with two buttons (upvote / downvote). 我正在制作一个带有两个按钮的投票系统(upvote / downvote)。 I've used input and label tags to create this, but there is a problem: 我已经使用输入和标签来创建它,但是有一个问题:

If I use radio buttons, I can either vote up or down, but I can't un-vote. 如果我使用单选按钮,我可以向上或向下投票,但我不能不投票。

If I use checkboxes, I can un-vote, but I can also vote both up and down. 如果我使用复选框,我可以取消投票,但我也可以上下投票。

What I want to achieve is being able to only vote up or down while also being able to remove the vote (think reddit). 我想要实现的是只能投票或者投票,同时还能够取消投票(想想reddit)。

I've thoroughly looked for an answer and I've come to find that this is not possible to do with CSS. 我已经彻底找到了答案,我发现这不可能与CSS有关。 There are a lot of scripts out there, the problem is I have no idea about JavaScript or jQuery, so I don't know how to implement the code. 有很多脚本,问题是我不知道JavaScript或jQuery,所以我不知道如何实现代码。

I think the easiest solution would be unchecking the downvote button when I click on upvote and vice versa, but again, I have no idea how this code would look like or how to implement it. 我认为最简单的解决方案是在点击upvote时取消选中downvote按钮,反之亦然,但同样,我不知道这段代码的样子或如何实现它。

Maybe there's an easier solution using pure CSS to change the appearance of the other button even after it has been checked? 也许有一个更容易的解决方案使用纯CSS来改变其他按钮的外观,即使它被检查后? I don't know, but I'd much rather use such a solution if it exists. 我不知道,但如果它存在,我宁愿使用这样的解决方案。

My code: 我的代码:

 input[type=radio] { display: none } #up { width: 20px; height: 16px; background: url(http://c.thumbs.redditmedia.com/Y5Gt7Gtk59BlV-3t.png) left top; position: absolute; left: 50px; top: 50px } #down { width: 20px; height: 16px; background: url(http://c.thumbs.redditmedia.com/Y5Gt7Gtk59BlV-3t.png) left bottom; opacity: 0.5; position: absolute; left: 50px; top: 84px } #vote { width: 21px; height: 18px; text-align: center; font-size: 26px; line-height: 18px; position: absolute; left: 50px; top: 66px; z-index: -1 } #up:hover { background-position: top; cursor: pointer } #upvote:checked ~ #up { background-position: top; } #upvote:checked ~ #vote { color: #DC5B28; z-index: 1 } #down:hover { background-position: bottom; cursor: pointer; opacity: 1 } #downvote:checked ~ #down { background-position: bottom; opacity: 1 } #downvote:checked ~ #vote { color: #3580DD } #no { position: absolute; display: none; background: url(http://c.thumbs.redditmedia.com/Y5Gt7Gtk59BlV-3t.png) } #upvote:checked ~ #no { display: block; background-position: left top; left: 50px; top: 50px } #downvote:checked ~ #no { display: block; background-position: left bottom; left: 50px; top: 84px; opacity: 0.5 } 
 <input type="radio" name="vote" value="+1" id="upvote"> <label for="upvote" id="up"></label> <input type="radio" name="vote" value="-1" id="downvote"> <label for="downvote" id="down"></label> <input type="radio" name="vote" value="0" id="novote"> <label for="novote" id="no"></label> <div id="vote">•</div> 

If you want a CSS-only solution, you can try adding a default hidden third option, which represents no vote. 如果您想要一个仅限CSS的解决方案,您可以尝试添加一个默认隐藏的第三个选项,它代表没有投票。

Then, when user upvotes or downvotes, that third option is shown, and it overlaps the chosen option. 然后,当用户upvotes或downvotes时,显示第三个选项,并且它与所选选项重叠。

Therefore, when the user thinks he is clicking the chosen option again, he is in fact choosing the no vote option. 因此,当用户认为他再次点击所选择的选项时,他实际上是选择无投票选项。

 #vote { position: relative; } #vote > input { display: none; /* Hide radio buttons */ } #vote > label { cursor: pointer; display: block; width: 0; border: 50px solid; /* We will make them look like... */ border-color: black transparent; /* ...triangles using borders */ } #upvote + label { border-top: none; /* Triangulating */ } #downvote + label { border-bottom: none; /* Triangulating */ margin-top: 15px; /* Space between triangles */ } #vote > input:checked + label { border-color: orange transparent; /* Highlight chosen option */ } #vote > #novote-label { display: none; /* Hide it by default */ position: absolute; /* Take it out of the normal flow */ border-top: none; border-color: transparent; } #upvote:checked ~ #novote-label { /* Display it overlapping upvote */ display: block; top: 0; } #downvote:checked ~ #novote-label { /* Display it overlapping downvote */ display: block; bottom: 0; } 
 <div id="vote"> <input type="radio" name="vote" value="+1" id="upvote" /> <label for="upvote"></label> <input type="radio" name="vote" value="-1" id="downvote" /> <label for="downvote"></label> <input type="radio" name="vote" value="0" id="novote" /> <label for="novote" id="novote-label"></label> </div> 

With few changes it can be keyboard accessible too: 几乎没有变化,它也可以通过键盘访问:

 #vote { position: relative; } #vote > input { /* Hiding in a keyboard-accesible way */ opacity: 0; position: absolute; z-index: -1; } #vote > input:focus + label { outline: 1px dotted #999; /* Keyboard friendly */ } #vote > label { cursor: pointer; display: block; width: 0; border: 50px solid; /* We will make them look like... */ border-color: black transparent; /* ...triangles using borders */ } #upvote + label { border-top: none; /* Triangulating */ } #downvote + label { border-bottom: none; /* Triangulating */ margin-top: 15px; /* Space between triangles */ } #vote > input:checked + label { border-color: orange transparent; /* Highlight chosen option */ } #vote > #novote-label { display: none; /* Hide it by default */ position: absolute; /* Take it out of the normal flow */ border-top: none; border-color: transparent; } #upvote:checked ~ #novote-label { /* Display it overlapping upvote */ display: block; top: 0; } #downvote:checked ~ #novote-label { /* Display it overlapping downvote */ display: block; bottom: 0; } 
 <div id="vote"> <input type="radio" name="vote" value="+1" id="upvote" /> <label for="upvote"></label> <input type="radio" name="vote" value="-1" id="downvote" /> <label for="downvote"></label> <input type="radio" name="vote" value="0" id="novote" /> <label for="novote" id="novote-label"></label> </div> 

The snippets above uses borders to simulate triangles/arrows. 上面的片段使用边框来模拟三角形/箭头。 Similarly, background images can be used too. 类似地,也可以使用背景图像。

 #vote { position: relative; } #vote > input { display: none; } #vote > label { cursor: pointer; display: block; width: 20px; height: 16px; background-image: url('http://i.stack.imgur.com/36F2b.png'); } #vote > #up { background-position: left top; } #vote > #down { background-position: left bottom; } #upvote:checked ~ #up { background-position: top; } #downvote:checked ~ #down { background-position: bottom; } #vote > #no { display: none; position: absolute; background: none; } #upvote:checked ~ #no { display: block; top: 0; } #downvote:checked ~ #no { display: block; bottom: 0; } 
 <div id="vote"> <input type="radio" name="vote" value="+1" id="upvote" /> <label for="upvote" id="up"></label> <input type="radio" name="vote" value="-1" id="downvote" /> <label for="downvote" id="down"></label> <input type="radio" name="vote" value="0" id="novote" /> <label for="novote" id="no"></label> </div> 

You have a pure CSS solution, here's a javascript version. 你有一个纯CSS解决方案,这是一个javascript版本。 It puts a click listener on an ancestor of the "vote" buttons. 它在“投票”按钮的祖先上放置了一个点击监听器。 When a button is clicked and checked, it unchecks the other vote buttons in the same container so only one vote is checked at a time. 单击并选中某个按钮时,它会取消选中同一容器中的其他投票按钮,这样一次只能检查一个投票。 It will work with any number of vote buttons (you might have say +1, +2, etc.). 它可以使用任意数量的投票按钮(你可能会说+1,+ 2等)。

If clicking on the checkbox unchecks it, eg when cancelling a vote, the function does nothing. 如果单击该复选框取消选中它,例如取消投票时,该功能不执行任何操作。 Make sure the script is placed after the container, or use the load event. 确保脚本放在容器之后,或使用load事件。 The listener can be attached to as many containers as you like, just as long as each only contains one set of buttons. 只要每个容器只包含一组按钮,就可以将监听器连接到任意数量的容器。

<!-- A container for the vote buttons -->
<div id="voteContainer">
  <input type="checkbox" name="vote" value="+1" id="upvote">
  <label for="upvote" id="up">Up</label>
  <br>
  <input type="checkbox" name="vote" value="-1" id="downvote">
  <label for="downvote" id="down">Down</label>
</div>

<script>
(function() {
  var div = document.getElementById('voteContainer');
  if (div) div.onclick = setVote;

  // Looks at the state of els
  function setVote(event) {
    event = event || window.event;
    var target = event.target || event.srcElement;


    // If target checkbox is checked, uncheck all others
    if (target.checked) {
      var els = this.querySelectorAll('input[name=' + target.name + ']')

      for (var i=0; i<els.length; i++) {
        els[i].checked = els[i] === target;
      }
    }
  }
}());
</script>

The above should work in all modern browsers and IE back to IE 8. If it needs to work in older browsers, that can be done pretty easily, especially if there is only one set of vote buttons in the page (it requires a small modification to the var els = ... line). 以上应该适用于所有现代浏览器和IE回到IE 8.如果它需要在旧版浏览器中工作,这可以很容易地完成,特别是如果页面中只有一组投票按钮(它需要一个小的修改到var els = ... line)。

The label elements don't need an ID for the script to work. 标签元素不需要ID来使脚本起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM