W Gmailu użytkownik może kliknąć jedno pole wyboru na liście e-maili, przytrzymać klawisz Shift i zaznaczyć drugie pole wyboru. JavaScript następnie zaznaczy / odznaczy pola wyboru znajdujące się między dwoma polami wyboru.
Ciekawi mnie, jak to się robi? Czy to JQuery czy jakiś podstawowy (lub złożony) JavaScript?
javascript
gmail
Askaloński
źródło
źródło
Odpowiedzi:
Napisałem samodzielne demo, które używa 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>
źródło
.prop('checked'
, a nie.attr('checked'
. jsFiddle: jsfiddle.net/dn4jv9a5Odbywa się to za pomocą dość prostego kodu JavaScript.
Śledzą identyfikator ostatniego zaznaczonego pola, a gdy zaznaczone jest inne pole wyboru, używają atrybutu zdarzenia shiftKey, aby sprawdzić, czy przesunięcie zostało wstrzymane podczas klikania pola wyboru. Jeśli tak, ustawiają zaznaczoną właściwość każdego pola wyboru między nimi na true.
Aby określić, kiedy pole jest zaznaczone, prawdopodobnie używają zdarzenia onclick na polach wyboru
źródło
Niedawno napisałem wtyczkę jQuery, która zapewnia tę funkcję i nie tylko.
Po dołączeniu wtyczki wystarczy zainicjować kontekst pól wyboru za pomocą następującego fragmentu kodu:
$('#table4').checkboxes({ range: true });
Oto link do dokumentacji, wersji demonstracyjnej i do pobrania: http://rmariuzzo.github.io/checkboxes.js/
źródło
Wygląda na to, że każda odpowiedź, jaką mogę znaleźć w Internecie, jest całkowicie zależna od jQuery. JQuery dodaje bardzo niewiele funkcjonalności. Oto szybka wersja, która nie wymaga żadnych frameworków:
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; }); } }
A następnie zainicjuj go, kiedy tylko potrzebujesz:
allow_group_select_checkboxes('[id of a wrapper that contains the checkboxes]')
źródło
Cóż, post jest dość stary, ale oto rozwiązanie, z którym właśnie się spotkałem: wtyczka jQuery Field
źródło
Mam to rozwiązanie z http://abcoder.com/javascript/jquery/simple-check-uncheck-all-jquery-function/ (teraz nie żyje) :
JavaScript i kod 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>
źródło
Zainspirowana drobnymi odpowiedziami, oto prosta wersja JavaScript używająca
Array.prototype
do wymuszania list węzłów na używaniu funkcji tablicowych zamiastfor
pętli.(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>
źródło
Naprawdę podobał mi się przykład gyo i dodałem trochę kodu, więc działa na wszystkich polach wyboru o tej samej nazwie.
Dodałem również MutationObserver, więc zdarzenia są również obsługiwane na nowo dodanych polach wyboru.
$(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>
źródło
Pobrałem wersję jQuery z @BC. i przekształcił go w wersję ES6, ponieważ kod w rzeczywistości dość elegancko rozwiązuje problem, na wypadek, gdyby ktoś nadal się z tym spotkał ...
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; } ) ); }
źródło
Znalazłem lepsze rozwiązanie, które działa zarówno w przypadku zaznaczania, jak i usuwania zaznaczenia pól wyboru.
Używa rdzenia javascript i 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>
źródło
Oto kolejna implementacja podobna do wielokrotnego wyboru Outlooka.
<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]; } } }); });
źródło
Oto rozwiązanie jquery, które napisałem i używam:
chksel
chksel_index
Ponadto każdy
checkbox
ma atrybut o nazwie,rg
który zawiera ten sam indeksvar 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');}
})
źródło
to rozwiązanie działa u mnie, również Ajax oparty na 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>
źródło