如何像GMail一样选择多个复选框?

97
在GMail中,用户可以在邮件列表中单击一个复选框,按住Shift键,然后选择第二个复选框。接着JavaScript会选择/取消两个复选框之间的所有复选框。
我想知道这是如何实现的?这是使用jQuery还是一些基本(或复杂)的JavaScript?

4
@BC的答案易于查找的gist链接是 https://gist.github.com/3784055。 - Andy Ray
我想知道是否有一个浏览器可以默认完成这个功能?当复选框是列表时,我期望它可以“自动工作”。 - yellowsir
15个回答

209

我写了一个使用jquery的自包含演示:

$(document).ready(function() {
    var $chkboxes = $('.chkbox');
    var lastChecked = null;

    $chkboxes.click(function(e) {
        if (!lastChecked) {
            lastChecked = this;
            return;
        }

        if (e.shiftKey) {
            var start = $chkboxes.index(this);
            var end = $chkboxes.index(lastChecked);

            $chkboxes.slice(Math.min(start,end), Math.max(start,end)+ 1).prop('checked', lastChecked.checked);
        }

        lastChecked = this;
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<head>
</head>
<body>
    <input type="checkbox" id="id_chk1" class="chkbox" value="1" />Check 1<br/>
    <input type="checkbox" id="id_chk2" class="chkbox" value="2" />Check 2<br/>
    <input type="checkbox" id="id_chk3" class="chkbox" value="3" />Check 3<br/>
    <input type="checkbox" id="id_chk4" class="chkbox" value="4" />Check 4<br/>
    <input type="checkbox" id="id_chk5" class="chkbox" value="5" />Check 5<br/>
    <input type="checkbox" id="id_chk6" class="chkbox" value="6" />Check 6<br/>
    <input type="checkbox" id="id_chk7" class="chkbox" value="7" />Check 7<br/>
</body>
</html>


8
你可以使用"slice"方法来代替使用"for"循环。代码如下:"$('.chkbox').slice(min..., max... + 1).attr('checked', lastChecked.checked)" - Matthew Crumley
11
回答如果没有抽象化的jQuery插件就很无力。因此,这里有一个链接:https://gist.github.com/3784055,你可以在那里找到它。 - Andy Ray
3
在取消选中某些复选框后多次使用 Shift+单击时似乎无法起作用。http://jsfiddle.net/5fG5b/ - Greg Pettit
3
这是因为应该使用.prop('checked'而不是.attr('checked'。jsFiddle链接:http://jsfiddle.net/dn4jv9a5/ - caitlin
4
@schnauss 谢谢你,你是对的,我已经更新了答案。为了为自己辩护,原始答案是在 prop() 可用之前编写的。 - BC.
我还想一次取消选择多个框,最好也能用 shift-click。如何更改示例? - Stefan Reich

37

这是通过相对简单的JavaScript来完成的。

他们跟踪最后一个选中复选框的id,当另一个复选框被选中时,使用shiftKey事件属性查看是否在点击复选框时按下了shift键。如果是,则将两个之间的每个复选框的checked属性设置为true。

要确定何时选中某个框,他们可能会在复选框上使用onclick事件


3
如果您想要的话,可以使用 Mozilla 开发者网络提供的这些参考资料:shiftKey 事件属性Input 元素属性onclick - PhoneixS

15

似乎我在网上找到的每一个答案都完全依赖于jQuery。但是jQuery只增加了极少的功能。这里有一个快速版本,不需要任何框架:

function allow_group_select_checkboxes(checkbox_wrapper_id){
    var lastChecked = null;
    var checkboxes = document.querySelectorAll('#'+checkbox_wrapper_id+' input[type="checkbox"]');

    //I'm attaching an index attribute because it's easy, but you could do this other ways...
    for (var i=0;i<checkboxes.length;i++){
        checkboxes[i].setAttribute('data-index',i);
    }

    for (var i=0;i<checkboxes.length;i++){
        checkboxes[i].addEventListener("click",function(e){

            if(lastChecked && e.shiftKey) {
                var i = parseInt(lastChecked.getAttribute('data-index'));
                var j = parseInt(this.getAttribute('data-index'));
                var check_or_uncheck = this.checked;

                var low = i; var high=j;
                if (i>j){
                    var low = j; var high=i; 
                }

                for(var c=0;c<checkboxes.length;c++){
                    if (low <= c && c <=high){
                        checkboxes[c].checked = check_or_uncheck;
                    }   
                }
            } 
            lastChecked = this;
        });
    }
}

然后在需要时初始化它:

allow_group_select_checkboxes('[id of a wrapper that contains the checkboxes]')

"jQuery添加了非常少的功能"<3 谢谢您。 - Jan Mirus

14

最近,我写了一个jQuery插件,提供了这个功能以及更多。

包含该插件之后,您只需要使用以下代码片段初始化复选框的上下文:

$('#table4').checkboxes({ range: true });

这里是文档、演示和下载链接:http://rmariuzzo.github.io/checkboxes.js/


3

我从http://abcoder.com/javascript/jquery/simple-check-uncheck-all-jquery-function/(目前已失效)中得到了这个解决方案:

JavaScript和HTML代码

var NUM_BOXES = 10;

// last checkbox the user clicked
var last = -1;

function check(event) {
  // in IE, the event object is a property of the window object
  // in Mozilla, event object is passed to event handlers as a parameter
  if (!event) { event = window.event }
  var num = parseInt(/box\[(\d+)\]/.exec(this.name)[1]);
  if (event.shiftKey && last != -1) {
     var di = num > last ? 1 : -1;
     for (var i = last; i != num; i += di) {
        document.forms.boxes['box[' + i + ']'].checked = true;
     }
  }
  last = num;
}

function init() {
  for (var i = 0; i < NUM_BOXES; i++) {
    document.forms.boxes['box[' + i + ']'].onclick = check;
  }
}
<body onload="init()">
    <form name="boxes">
    <input name="box[0]" type="checkbox">
    <input name="box[1]" type="checkbox">
    <input name="box[2]" type="checkbox">
    <input name="box[3]" type="checkbox">
    <input name="box[4]" type="checkbox">
    <input name="box[5]" type="checkbox">
    <input name="box[6]" type="checkbox">
    <input name="box[7]" type="checkbox">
    <input name="box[8]" type="checkbox">
    <input name="box[9]" type="checkbox">
    </form>
</body>


链接域名已不再使用。 - Zaren Wienclaw

3

好的,这篇文章相对较旧,但我刚刚找到了一个解决方案: jQuery Field 插件


3
我将jQuery版本从 @BC. 中取出,并转化为ES6版本,因为代码实际上相当优雅地解决了这个问题,以防有人仍然遇到困难...
function enableGroupSelection( selector ) {
  let lastChecked = null;
  const checkboxes = Array.from( document.querySelectorAll( selector ) );

  checkboxes.forEach( checkbox => checkbox.addEventListener( 'click', event => {
    if ( !lastChecked ) {
      lastChecked = checkbox;

      return;
    }

    if ( event.shiftKey ) {
      const start = checkboxes.indexOf( checkbox );
      const end   = checkboxes.indexOf( lastChecked );

      checkboxes
        .slice( Math.min( start, end ), Math.max( start, end ) + 1 )
        .forEach( checkbox => checkbox.checked = lastChecked.checked );
    }

    lastChecked = checkbox;
  } ) );
}

2

在受到优秀答案的启发下,这里提供了一个简单的JavaScript版本,使用Array.prototype来强制nodelist使用数组函数,而不是for循环。

(function () { // encapsulating variables with IIFE
  var lastcheck = null // no checkboxes clicked yet

  // get desired checkboxes
  var checkboxes = document.querySelectorAll('div.itemslist input[type=checkbox]')

  // loop over checkboxes to add event listener
  Array.prototype.forEach.call(checkboxes, function (cbx, idx) {
    cbx.addEventListener('click', function (evt) {

      // test for shift key, not first checkbox, and not same checkbox
      if ( evt.shiftKey && null !== lastcheck && idx !== lastcheck ) {

        // get range of checks between last-checkbox and shift-checkbox
        // Math.min/max does our sorting for us
        Array.prototype.slice.call(checkboxes, Math.min(lastcheck, idx), Math.max(lastcheck, idx))
          // and loop over each
          .forEach(function (ccbx) {
            ccbx.checked = true
        })
      }
      lastcheck = idx // set this checkbox as last-checked for later
    })
  })
}())
<div class="itemslist">
  <input type="checkbox" name="one"   value="1">
  <input type="checkbox" name="two"   value="2">
  <input type="checkbox" name="three" value="3">
  <input type="checkbox" name="four"  value="4">
  <input type="checkbox" name="five"  value="5">
</div>


如何通过取消选择功能进行改进? - TarasH

2

我很喜欢gyo的示例,并添加了一些代码,使其适用于所有具有相同名称的复选框。

我还添加了一个MutationObserver,以便在新添加的复选框上处理事件。

最初的回答

$(document).ready(function() {
    var previouslyClicked = {};

    var rangeEventHandler = function(event) {
        if (event.shiftKey && previouslyClicked[this.name] && this != previouslyClicked[this.name]) {
            var $checkboxes = $('input[type=checkbox][name='+this.name+']').filter(':visible');
            var start = $checkboxes.index( this );
            var end = $checkboxes.index( previouslyClicked[this.name] );
//              console.log('range', start, end, this, previouslyClicked[this.name]);
            $checkboxes.slice(Math.min(start,end), Math.max(start,end)+ 1).prop('checked', previouslyClicked[this.name].checked);
        } else {
            previouslyClicked[this.name] = this;
        }
    };

    if ("MutationObserver" in window) { // https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/MutationObserver to refresh on new checkboxes
        var mutationCallback = function(mutationList, observer) {
            mutationList.forEach((mutation) => {
                mutation.addedNodes.forEach((node) => {
                    if (node.nodeName == 'INPUT' && node.type == 'checkbox') {
                        $(node).on('click.selectRange', rangeEventHandler);
                    }
                });
            });
        };

        var observer = new MutationObserver(mutationCallback);
        observer.observe(document, {
            childList: true,
            attributes: false,  // since name is dynamically read
            subtree: true
        });
    }

    $('input[type=checkbox][name]').on('click.selectRange', rangeEventHandler);
});
<html>
<head>
</head>
<body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <div>
    First:
    <input type="checkbox" name="first">
    <input type="checkbox" name="first">
    <input type="checkbox" name="first">
    <input type="checkbox" name="first">
    <input type="checkbox" name="first">
  </div>
  <div>
    Second:
    <input type="checkbox" name="second">
    <input type="checkbox" name="second">
    <input type="checkbox" name="second">
    <input type="checkbox" name="second">
    <input type="checkbox" name="second">
  </div>
</body>
</html>


1
  • 找到了更好的解决方案,它适用于选择和取消选择复选框。

  • 使用核心JavaScript和jQuery。

$(document).ready(function() {
    var $chkboxes = $('.chkbox');
    var lastChecked = null;

    $chkboxes.click(function(e) {
        if(!lastChecked) {
            lastChecked = this;
            return;
        }

        if(e.shiftKey) {
            var start = $chkboxes.index(this);
            var end = $chkboxes.index(lastChecked);

            $chkboxes.slice(Math.min(start,end), Math.max(start,end)+ 1).prop('checked', e.target.checked);

        }

        lastChecked = this;
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
    <head>
    </head>
    <body>
        <input type="checkbox" id="id_chk1" class="chkbox" value="1" />Check 1<br/>
        <input type="checkbox" id="id_chk2" class="chkbox" value="2" />Check 2<br/>
        <input type="checkbox" id="id_chk3" class="chkbox" value="3" />Check 3<br/>
        <input type="checkbox" id="id_chk4" class="chkbox" value="4" />Check 4<br/>
        <input type="checkbox" id="id_chk5" class="chkbox" value="5" />Check 5<br/>
        <input type="checkbox" id="id_chk6" class="chkbox" value="6" />Check 6<br/>
        <input type="checkbox" id="id_chk7" class="chkbox" value="7" />Check 7<br/>
    </body>
</html>


1
这实际上只是上面被接受的答案的复制。 - Jargs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接