【问题标题】:How can I shift-select multiple checkboxes like GMail?如何切换选择多个复选框,例如 GMail?
【发布时间】:2017-10-14 08:58:31
【问题描述】:

在 GMail 中,用户可以单击电子邮件列表中的一个复选框,按住 Shift 键,然后选择第二个复选框。然后,JavaScript 将选择/取消选择两个复选框之间的复选框。

我很好奇这是怎么做到的?这是 JQuery 还是一些基本(或复杂)的 JavaScript?

【问题讨论】:

标签: javascript gmail


【解决方案1】:

这是通过相当简单的 javascript 完成的。

他们跟踪最后一个复选框的 id,当另一个复选框被选中时,他们使用shiftKey event attribute 来查看在单击复选框时是否保留了 shift。如果是这样,他们将两者之间的每个复选框的 checked property 设置为 true。

为了确定一个框何时被选中,他们可能会在复选框上使用onclick 事件

【讨论】:

【解决方案2】:

我编写了一个使用 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>

【讨论】:

  • 您可以调用 slice 而不是使用 for 循环。它看起来像这样:“$('.chkbox').slice(min..., max... + 1).attr('checked', lastChecked.checked)"
  • 如果没有抽象的 jquery 插件,答案是蹩脚的。所以给你gist.github.com/3784055
  • 在取消选中某些没有按 shift 键的框后多次按 shift 键似乎不起作用。 jsfiddle.net/5fG5b
  • 那是因为它应该是.prop('checked',而不是.attr('checked'。 jsFiddle:jsfiddle.net/dn4jv9a5
  • @schnauss 谢谢,你是对的,我已经更新了答案。在我的辩护中,原始答案是在 prop() 可用之前编写的
【解决方案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>

【讨论】:

  • Links 域不再使用。
【解决方案4】:

好吧,这篇文章已经很老了,但这是我刚刚遇到的一个解决方案: jQuery Field Plug-In

【讨论】:

    【解决方案5】:

    这是我编写和使用的 jquery 解决方案:

    • 所有复选框都有同一个类,名为chksel
    • 为了更快地进行个人选择,班级将执行订单 命名为chksel_index
    • 此外,每个checkbox 都有一个名为rg 的属性,其中包含相同的 索引

      var chksel_last=-1;
      $('.chksel').click(function(ev){
         if(ev.shiftKey){var i=0;
            if(chksel_last >=0){
              if($(this).attr('rg') >= chksel_last){
               for(i=chksel_last;i<=$(this).attr('rg');i++){$('.chksel_'+i).attr('checked','true')}}
              if($(this).attr('rg') <= chksel_last){for(i=$(this).attr('rg');i<=chksel_last;i++){$('.chksel_'+i).attr('checked','true')}}
            }  
            chksel_last=$(this).attr('rg');
         }else{chksel_last=$(this).attr('rg');}
      

      })

    【讨论】:

      【解决方案6】:

      最近,我编写了一个 jQuery 插件来提供该功能等等。

      包含插件后,您只需使用以下代码 sn-p 初始化复选框的上下文:

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

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

      【讨论】:

        【解决方案7】:

        这也是另一个类似于 Outlooks 多选的实现..

            <script type="text/javascript">
        
        function inRange(x, range)
        {
            return (x >= range[0] && x <= range[1]);
        }
        
        $(document).ready(function() {
            var $chkboxes = $('.chkbox');
            var firstClick = 1;
            var lastClick = null;
            var range = [];
        
            $chkboxes.click(function(e) {
                if(!e.shiftKey && !e.ctrlKey) {
        
                    $('#index-' + firstClick).prop('checked', false);
        
                    firstClick = $chkboxes.index(this) + 1;
        
                    if (firstClick !== null && firstClick !== ($chkboxes.index(this)+1)) {
                        $('#index-' + firstClick).prop('checked', true);
                    }
                } else if (e.shiftKey) {
                    lastClick = $chkboxes.index(this) + 1;
                    if ((firstClick < lastClick) && !inRange(lastClick, range)) {
                        for (i = firstClick; i < lastClick; i++) {
                            $('#index-' + i).prop('checked', true);
                        }
                        range = [firstClick, lastClick];
                    } else if ((firstClick > lastClick) && !inRange(lastClick, range)) {
                        for (i = lastClick; i < firstClick; i++) {
                            $('#index-' + i).prop('checked', true);
                        }
                        range = [lastClick, firstClick];
                    } else if ((firstClick < lastClick) && inRange(lastClick, range)) {
                        for (i = 1; i < 100; i++) {
                            $('#index-' + i).prop('checked', false);
                        }
        
                        for (i = firstClick; i < lastClick; i++) {
                            $('#index-' + i).prop('checked', true);
                        }
                        range = [firstClick, lastClick];
                    }else if ((firstClick > lastClick) && inRange(lastClick, range)) {
                        for (i = 1; i < 100; i++) {
                            $('#index-' + i).prop('checked', false);
                        }
        
                        for (i = lastClick; i < firstClick; i++) {
                            $('#index-' + i).prop('checked', true);
                        }
                        range = [lastClick, firstClick];
                    }
                }
            });
        });
        

        【讨论】:

          【解决方案8】:

          似乎我可以在网上找到的每个答案都完全依赖于 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 添加的功能非常少"
          【解决方案9】:

          受所提供的精美答案的启发,这是一个纯 JavaScript 版本,使用 Array.prototype 强制节点列表使用数组函数,而不是 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>

          【讨论】:

          • 取消选择功能如何改进?
          【解决方案10】:

          我从@BC 获取了 jQuery 版本。并将其转换为 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;
            } ) );
          }
          

          【讨论】:

            【解决方案11】:

            我真的很喜欢 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>

            【讨论】:

              【解决方案12】:
              • 找到了适用于选择和取消选择复选框的更好解决方案。

              • 使用核心 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>

              【讨论】:

              • 这实际上是上面接受的答案的副本。
              【解决方案13】:

              此解决方案适用于我,也适用于 DataTables https://jsfiddle.net/6ouhv7bw/4/

              <table id="dataTable">
              
              <tbody>
              <tr>
              <td><input type="checkbox"></td>
              </tr>
              
              <tr>
              <td><input type="checkbox"></td>
              </tr>
              
              <tr>
              <td><input type="checkbox"></td>
              </tr>
              
              <tr>
              <td><input type="checkbox"></td>
              </tr>
              </tbody>
              </table>
              
              <script>
              $(document).ready(function() {
                 var $chkboxes = $('#dataTable');
              var $range = '#dataTable tbody';
              var $first = false;
              var $indexWrapp = 'tr';
              var lastChecked = null;
              var $checkboxes = 'input[type="checkbox"]';
              
              $chkboxes.on('click',$checkboxes,function(e) {
              
                  if ($first===false) {
              
                      lastChecked = $(this).closest($indexWrapp).index();
                      lastCheckedInput = $(this).prop('checked');
                      $first=true;
                      return;
                  }
              
                  if (e.shiftKey) {
              
                      var start = lastChecked;
                      var end =  $(this).closest($indexWrapp).index();
              
                     $( $range+' '+$indexWrapp).each(function() {
                        $currIndex=$(this).index();
                        if( $currIndex>=start && $currIndex<=end ){
                            $(this).find($checkboxes).prop('checked', lastCheckedInput);
                        }
              
                     })
                  }
              
                   lastCheckedInput = $(this).prop('checked');
                   lastChecked = $(this).closest($indexWrapp).index();
              });
              </script>
              

              【讨论】:

                【解决方案14】:

                这里是优雅的实现。想法是将第一个选择的输入存储到 lastChecked 变量中,当用户使用 shiftKey 选择输入字段时,我们将运行一个循环并切换 inBetween(boolean) 并将所有复选框标记为真值。 灵感来自 Wesbos。

                let checkboxes= document.querySelectorAll('.wrapper input[type="checkbox"]');
                let lastChecked;
                
                function logic(e)
                {
                let inBetween= false;   
                if(e.shiftKey)
                {
                  checkboxes.forEach(checkbox=>{
                    if(checkbox===this  || checkbox===lastChecked)
                    {
                      inBetween =!inBetween;
                    }
                    if(inBetween) checkbox.checked=true;
                    
                  })             
                }
                 lastChecked= this;   
                }
                
                checkboxes.forEach((checkbox,i) => checkbox.addEventListener('click',logic));
                
                .wrapper{
                 display: flex;
                 flex-direction: column;
                }
                
                <div class="wrapper">
                  <input type="checkbox" name="one">
                  <input type="checkbox" name="two">
                  <input type="checkbox" name="three">
                  <input type="checkbox" name="four">
                  <input type="checkbox" name="five">
                </div>
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-02-05
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-12-07
                  • 2012-03-28
                  相关资源
                  最近更新 更多