ฉันจะเลื่อน - เลือกช่องทำเครื่องหมายหลายช่องเช่น GMail ได้อย่างไร


86

ใน GMail ผู้ใช้สามารถคลิกที่ช่องทำเครื่องหมายหนึ่งช่องในรายการอีเมลกดปุ่ม Shift ค้างไว้แล้วเลือกช่องทำเครื่องหมายที่สอง จากนั้น JavaScript จะเลือก / ยกเลิกการเลือกช่องทำเครื่องหมายที่อยู่ระหว่างสองช่องทำเครื่องหมาย

ฉันอยากรู้ว่ามันเป็นอย่างไร? 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
คุณสามารถเรียก slice แทนการใช้ for loop จะมีลักษณะดังนี้: "$ ('. 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 ขอบคุณคุณพูดถูกและฉันได้อัปเดตคำตอบแล้ว ในการป้องกันของฉันคำตอบเดิมถูกเขียนขึ้นก่อนที่จะมี prop ()
BC

36

สิ่งนี้ทำได้โดยใช้จาวาสคริปต์ที่ค่อนข้างเรียบง่าย

พวกเขาติดตาม id ของช่องที่ทำเครื่องหมายล่าสุดและเมื่อมีการทำเครื่องหมายในช่องอื่นพวกเขาจะใช้แอตทริบิวต์เหตุการณ์ shiftKeyเพื่อดูว่ามีการเลื่อนขณะที่คลิกช่องทำเครื่องหมายหรือไม่ หากเป็นเช่นนั้นพวกเขาตั้งค่าคุณสมบัติที่ถูกตรวจสอบของแต่ละช่องทำเครื่องหมายระหว่างสองช่องเป็นจริง

เพื่อตรวจสอบว่าเมื่อใดที่มีการทำเครื่องหมายในช่องพวกเขาอาจใช้เหตุการณ์onclickในช่องทำเครื่องหมาย


2
หากคุณต้องการคุณสามารถใช้การอ้างอิงจาก Mozilla ผู้พัฒนาเครือข่าย: shiftKey แอตทริบิวต์เหตุการณ์ , คุณสมบัติขององค์ประกอบการป้อนข้อมูล , onclick
PhoneixS

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 code

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

2

ได้รับแรงบันดาลใจจากคำตอบที่ดีนี่คือเวอร์ชัน JavaScript ธรรมดาที่ใช้Array.prototypeเพื่อบังคับให้ nodelists ใช้ฟังก์ชันอาร์เรย์แทนการ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

ฉันเอาเวอร์ชั่น 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;
  } ) );
}

1
  • พบวิธีแก้ปัญหาที่ดีกว่าซึ่งใช้ได้กับทั้งเลือกและยกเลิกการเลือกช่องทำเครื่องหมาย

  • ใช้จาวาสคริปต์หลักและ 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

นี่คือการใช้งานอื่นที่คล้ายกับ 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];
            }
        }
    });
});


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

วิธีนี้ใช้ได้กับฉันเช่นกัน ajax ที่ใช้ 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>

0

นี่คือการใช้งานที่สง่างาม แนวคิดคือการจัดเก็บอินพุตแรกที่เลือกไว้ในตัวแปร lastChecked และเมื่อผู้ใช้เลือกฟิลด์อินพุตด้วย shiftKey เราจะเรียกใช้ลูปและสลับ inBetween (บูลีน) และทำเครื่องหมายในช่องทำเครื่องหมายทั้งหมดด้วยค่าจริง แรงบันดาลใจจาก 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>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.