自动选中/取消选中“全部”;复选框

Auto check/uncheck the "All" checkbox

本文关键字:复选框 全部 取消      更新时间:2023-09-26

我是JS的新手,我有一个有2个过滤器的页面,我被卡住了,我正在尝试:

  1. 如果过滤器的其他复选框都被选中,则自动选中(全部)复选框。

  2. 当用户选中复选框时,自动取消选中(全部)复选框。

我正在尝试下面的代码,但它不是真的工作…

HTML:

<div id="filter1">
<form action='#'>
<input type="checkbox" value="all" class="select-all" checked>(All)
<br>
<input type="checkbox" value="v1" class="checkboxlistitem" checked>F1: Value1
<br>
<input type="checkbox" value="v2" class="checkboxlistitem" checked>F1: Value2
<br>
<input type="checkbox" value="v3" class="checkboxlistitem" checked>F1: Value3
<br>
<input type="checkbox" value="v4" class="checkboxlistitem" checked>F1: Value4
<br>
<input type="submit" value="Apply">
</form>
</div>
<div id="filter2">
<form action='#'>
<input type="checkbox" value="all" class="select-all" checked>(All)
<br>
<input type="checkbox" value="v1" class="checkboxlistitem" checked>F2: Value1
<br>
<input type="checkbox" value="v2" class="checkboxlistitem" checked>F2: Value2
<br>
<input type="checkbox" value="v3" class="checkboxlistitem" checked>F2: Value3
<br>
<input type="checkbox" value="v4" class="checkboxlistitem" checked>F2: Value4
<br>
<input type="submit" value="Apply">
</form>
</div>

JS:

$(".checkboxlistitem").change(function() {
$(".select-all").prop("checked", $(".checkboxlistitem:checked").length ==    $(".checkboxlistitem").length);});

JSFIDDLE:

https://jsfiddle.net/Max06270/5scgbnww/

如果你需要澄清,请告诉我。提前感谢,马克斯

你的jquery选择器太通用了,所以它们影响了两个表单。下面应该是你想要的一个工作示例:

$(".select-all").change(function () {
    $(this).siblings().prop('checked', $(this).prop("checked"));
});
$(".checkboxlistitem").change(function() {
	  var checkboxes = $(this).parent().find('.checkboxlistitem');
    var checkedboxes = checkboxes.filter(':checked');
    if(checkboxes.length === checkedboxes.length) {
     $(this).parent().find('.select-all').prop('checked', true);
    } else {
    $(this).parent().find('.select-all').prop('checked', false);
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="filter1">
  <form action='#'>
    <input type="checkbox" value="all" class="select-all" checked>(All)<br>
    <input type="checkbox" value="v1" class="checkboxlistitem" checked>F1: Value1<br>
    <input type="checkbox" value="v2" class="checkboxlistitem" checked>F1: Value2<br>
    <input type="checkbox" value="v3" class="checkboxlistitem" checked>F1: Value3<br>
    <input type="checkbox" value="v4" class="checkboxlistitem" checked>F1: Value4<br>
    <input type="submit" value="Apply">
  </form> 
</div>
<br>
<div id="filter2">
  <form action='#'>
    <input type="checkbox" value="all" class="select-all" checked>(All)<br>
    <input type="checkbox" value="v1" class="checkboxlistitem" checked>F2: Value1<br>
    <input type="checkbox" value="v2" class="checkboxlistitem" checked>F2: Value2<br>
    <input type="checkbox" value="v3" class="checkboxlistitem" checked>F2: Value3<br>
    <input type="checkbox" value="v4" class="checkboxlistitem" checked>F2: Value4<br>
    <input type="submit" value="Apply">
  </form> 
</div>

https://jsfiddle.net/0epu6Lnn/

修复你的表单:

您的$('.checkboxlistitem')$('.checkboxlistitem:checked')的选择器选择所有具有这些类的元素,因此用于选择两个表单中的复选框。要解决这个问题,他们需要上下文。

在jQuery的事件回调中,this指的是事件被触发的元素。这意味着我们可以使用相对选择器来找到合适的元素:

// find the nearest ancestor that's a form
$form = $(this).closest('form');
// find all the `.checkboxlistitem` elements within the form
$checkboxes = $form.find('.checkboxlistitem');
// find the all checkbox within the form
$all = $form.find('.select-all');
// if there are any unchecked checkboxes the all option should be unchecked
$all.prop('checked', !$checkboxes.not(':checked').length);

// leaving this as it was in the jsfiddle
// Select/Unselect all chexboxes of the form
$(".select-all").change(function () {
    $(this).siblings().prop('checked', $(this).prop("checked"));
});
$('.checkboxlistitem').change(function () {
  var $form,
      $checkboxes,
      $all;
  
  // find the nearest ancestor that's a form
  $form = $(this).closest('form');
  
  // find all the `.checkboxlistitem` elements within the form
  $checkboxes = $form.find('.checkboxlistitem');
  
  // find the all checkbox within the form
  $all = $form.find('.select-all');
  
  // if there are any unchecked checkboxes the all option should be unchecked
  $all.prop('checked', !$checkboxes.not(':checked').length);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="filter1">
<form action='#'>
<input type="checkbox" value="all" class="select-all" checked>(All)
<br>
<input type="checkbox" value="v1" class="checkboxlistitem" checked>F1: Value1
<br>
<input type="checkbox" value="v2" class="checkboxlistitem" checked>F1: Value2
<br>
<input type="checkbox" value="v3" class="checkboxlistitem" checked>F1: Value3
<br>
<input type="checkbox" value="v4" class="checkboxlistitem" checked>F1: Value4
<br>
<input type="submit" value="Apply">
</form>
</div>
<div id="filter2">
<form action='#'>
<input type="checkbox" value="all" class="select-all" checked>(All)
<br>
<input type="checkbox" value="v1" class="checkboxlistitem" checked>F2: Value1
<br>
<input type="checkbox" value="v2" class="checkboxlistitem" checked>F2: Value2
<br>
<input type="checkbox" value="v3" class="checkboxlistitem" checked>F2: Value3
<br>
<input type="checkbox" value="v4" class="checkboxlistitem" checked>F2: Value4
<br>
<input type="submit" value="Apply">
</form>
</div>


这很好,但让我们通过改进表单的可访问性和部分完成的复选框列表的行为来提高它的水平。

形式可访问性

标签

如果你的复选框没有标签。

当然,您在它们后面添加了文本,但是屏幕阅读器无法知道每个复选框代表什么。

要解决这个问题,请使用<label>元素。

<form action="#">
  <label>
    <input type="checkbox" value="all" class="select-all" checked>
    (All)
  </label>
  <br>
  <label>
    <input type="checkbox" value="v1" class="checkboxlistitem" checked>
    F1: Value1
  </label>
  <br>
  ...
</form>

它们可以嵌套复选框,也可以让它们的[for]属性指向<input>元素的[id]属性,或者两者都有。

<form action="#">
  <input type="checkbox" id="f1-all" value="all" class="select-all" checked> <label for="f1-all">(All)</label>
  <br>
  <input type="checkbox" id="f1-v1" value="v1" class="checkboxlistitem" checked> <label for="f1-v1">F1: Value1</label>
  <br>
  ...
</form>

层次结构

在"all"复选框和单独的F#: Value#复选框之间有不同的层次关系。

要解决这个问题,使用<fieldset><legend>元素。
<form action="#">
  <fieldset>
    <legend>
      <label>
        <input type="checkbox" value="all" checked>
        <span>Select All in Filter 1</span>
      </label>
    </legend>
    <label>
      <input type="checkbox" value="v1" checked>
      <span>F1: Value1</span>
    </label>
    <br>
    ...
  </fieldset>
</form>

线分离

您目前使用<br>元素将字段分隔到不同的行。

常用<p>元素

<form action="#">
  <fieldset>
    <legend>...</legend>
    <p>
      <label>
        <input type="checkbox" value="v1" checked>
        <span>F1: Value1</span>
      </label>
    </p>
    ...
  </fieldset>
</form>

名称

您使用的是[value]属性,这很好,但是没有<input>元素具有[name]属性,这意味着数据不会被发送到服务器,并且在表单上调用jQuery的.serialize()将无法获得适当的数据。

在具有重要值的复选框上设置[name](不需要"all"复选框):

<form action="#">
  <fieldset>
    <legend>...</legend>
    <p>
      <label>
        <input type="checkbox" name="v1" value="1" checked>
        <span>F1: Value1</span>
      </label>
    </p>
    ...
  </fieldset>
</form>

或者,您可以将所有[name]属性设置为filter,并依赖于各种值来生成查询字符串,例如filter=v1&filter=v2,但这是一种高级技术,可能会在查询字符串解析中遇到错误,因此请谨慎操作。

部分完成复选框列表

虽然能够自动取消选中"all"复选框很好,但是当一些复选框被选中而其他复选框未选中时,未选中状态对于"all"复选框并不完全有意义。它不是在"none"也不是在"all"

进入不确定状态

复选框有第三种状态,只能在JavaScript中访问,这种状态正是为这种情况而设计的。

你可以通过切换复选框的indeterminate属性将其设置为不确定状态:

document.querySelector('input[type="checkbox"]').indeterminate = true;

或使用jQuery:

$('input[type="checkbox"]').first().prop('indeterminate', true);

检查列表是否处于不确定状态可以通过以下方法来完成:

  1. 未选中复选框
  2. 所有复选框已选中
  3. 一些复选框被选中和未选中

在实践中可能看起来像:

checkedCount = $checkboxes.filter(':checked').length;
if (!checkedCount) {
  // no checkboxes checked
  $all.prop({
    checked: false,
    indeterminate: false
  });
} else if (checkedCount === $checkboxes.length) {
  // all checkboxes checked
  $all.prop({
    checked: true,
    indeterminate: false
  });
} else {
  // some checkboxes checked and unchecked
  $all.prop({
    indeterminate: true
  });
}

All Together Now

上述内容的完整实现如下:

$('.filter').on('change', '[value="all"]', function () {
  var $form,
      $checkboxes,
      $all;
  
  $form = $(this).closest('form');
  $checkboxes = $form.find('[name="filter"]');
  $all = $form.find('[value="all"]');
  
  $checkboxes.prop('checked', $all.prop('checked'));
}).on('change', '[name="filter"]', function () {
  var $form,
      $checkboxes,
      $all,
      checkedCount;
  
  $form = $(this).closest('form');
  $checkboxes = $form.find('[name="filter"]');
  $all = $form.find('[value="all"]');
  
  checkedCount = $checkboxes.filter(':checked').length;
  
  if (!checkedCount) {
    // no checkboxes checked
    $all.prop({
      checked: false,
      indeterminate: false
    });
  } else if (checkedCount === $checkboxes.length) {
    // all checkboxes checked
    $all.prop({
      checked: true,
      indeterminate: false
    });
  } else {
    // some checkboxes checked and unchecked
    $all.prop({
      indeterminate: true
    });
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="filter1" class="filter">
  <form action='#'>
    <fieldset>
      <legend>
        <label>
          <input type="checkbox" value="all" checked>
          <span>Select All in Filter 1</span>
        </label>
      </legend>
      <p>
        <label>
          <input type="checkbox" name="filter" value="v1" checked>
          <span>F1: Value1</span>
        </label>
      </p>
      <p>
        <label>
          <input type="checkbox" name="filter" value="v2" checked>
          <span>F1: Value2</span>
        </label>
      </p>
      <p>
        <label>
          <input type="checkbox" name="filter" value="v3" checked>
          <span>F1: Value3</span>
        </label>
      </p>
      <p>
        <label>
          <input type="checkbox" name="filter" value="v4" checked>
          <span>F1: Value4</span>
        </label>
      </p>
    </fieldset>
    <input type="submit" value="Apply">
  </form>
</div>
<div id="filter2" class="filter">
  <form action='#'>
    <fieldset>
      <legend>
        <label>
          <input type="checkbox" value="all" checked>
          <span>Select All in Filter 2</span>
        </label>
      </legend>
      <p>
        <label>
          <input type="checkbox" name="filter" value="v1" checked>
          <span>F2: Value1</span>
        </label>
      </p>
      <p>
        <label>
          <input type="checkbox" name="filter" value="v2" checked>
          <span>F2: Value2</span>
        </label>
      </p>
      <p>
        <label>
          <input type="checkbox" name="filter" value="v3" checked>
          <span>F2: Value3</span>
        </label>
      </p>
      <p>
        <label>
          <input type="checkbox" name="filter" value="v4" checked>
          <span>F2: Value4</span>
        </label>
      </p>
    </fieldset>
    <input type="submit" value="Apply">
  </form>
</div>

对于那些想要使用普通js的人:

const checkboxes = document.getElementsByClassName("checkboxlistitem");
const selectAllBtn = document.getElementById("select-all");
for (let i = 0; i < checkboxes.length; i++) {
  checkboxes[i].addEventListener("change", () => {
    for (let i = 0; i < checkboxes.length; i++) {
      if (checkboxes[i].checked === false) {
        selectAllBtn.checked = false;
        break;
      } else {
        selectAllBtn.checked = true;
      }
    }
  });
}
// select all button
selectAllBtn.addEventListener("change", (event) => {
  for (let i = 0, n = checkboxes.length; i < n; i++) {
    checkboxes[i].checked = event.target.checked;
    
  }
});
<div id="filter1">
  <form action='#'>
    <input type="checkbox" value="all" id="select-all" checked>(All)<br>
    <input type="checkbox" value="v1" class="checkboxlistitem" checked>F1: Value1<br>
    <input type="checkbox" value="v2" class="checkboxlistitem" checked>F1: Value2<br>
    <input type="checkbox" value="v3" class="checkboxlistitem" checked>F1: Value3<br>
    <input type="checkbox" value="v4" class="checkboxlistitem" checked>F1: Value4<br>
    <input type="submit" value="Apply">
  </form> 
</div>