Gmailのような複数のチェックボックスをShiftキーを押しながら選択するにはどうすればよいですか?


86

Gmailでは、ユーザーはメーリングリストの1つのチェックボックスをクリックし、Shiftキーを押しながら、2番目のチェックボックスを選択できます。次に、JavaScriptは、2つのチェックボックスの間にあるチェックボックスを選択/選択解除します。

これがどのように行われるのか興味がありますか?これはJQueryですか、それとも基本的な(または複雑な)JavaScriptですか?


回答:


184

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
forループを使用する代わりにsliceを呼び出すことができます。次のようになります: "$( '。chkbox')。slice(min ...、max ... + 1).attr( 'checked'、lastChecked.checked)"
Matthew Crumley

10
抽象化されたjqueryプラグインがないと答えは不十分です。だからここに行くgist.github.com/3784055–
Andy Ray

3
Shiftキーを押しずにいくつかのボックスのチェックを外した後、Shiftキーを押しながらクリックを複数回実行しても機能しないようです。jsfiddle.net/5fG5b
Greg Pettit

3
それは.prop('checked'、ではなく、である必要があるため.attr('checked'です。jsFiddle:jsfiddle.net/dn4jv9a5
caitlin

3
@schnaussありがとう、あなたは正しいです、そして私は答えを更新しました。私の守備では、オリジナルの答えは(小道具の前に書かれた)利用可能でした
BC。

36

これは、かなり単純なjavascriptを介して行われます。

最後にチェックしたボックスのIDを追跡し、別のチェックボックスをオンにすると、shiftKeyイベント属性を使用して、チェックボックスをクリックしているときにシフトが保持されたかどうかを確認します。その場合、2つの間の各チェックボックスのcheckedプロパティをtrueに設定します。

ボックスがいつチェックされるかを決定するために、おそらくチェックボックスでonclickイベントを使用します


2
必要に応じて、Mozilla Developer Networkからの次の参照を使用できます:shiftKeyイベント属性入力要素のプロパティonclick
phoneixS 2012年

14

最近、私はその機能などを提供するjQueryプラグインを作成しました。

プラグインを含めた後、次のコードスニペットを使用してチェックボックスのコンテキストを初期化する必要があります。

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

ドキュメント、デモ、ダウンロードへのリンクは次のとおりです:http//rmariuzzo.github.io/checkboxes.js/


10

私がオンラインで見つけることができるすべての答えは、これを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]')


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 2018

2

提供された細かい答えに触発されて、ループArray.prototypeではなく配列関数を使用するようにノードリストを強制するために使用するプレーンなJavaScriptバージョンを次に示し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>


選択解除機能で改善するには?
RSH

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

@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;
  } ) );
}

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>


0

Outlookの複数選択に似た別の実装もあります。

    <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];
            }
        }
    });
});


0

これは私が作成して使用した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');}
    

    })


0

このソリューションは私にとってはうまくいきますが、DataTableshttps //jsfiddle.net/6ouhv7bw/4/に基づいたajaxでもあり ます

<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>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.