简体   繁体   中英

ALT+arrow keys to navigate between cells in table

Run the snippet below and focus the first input of the table.
Use the ALT key+any arrow key on your keyboard to navigate between the cells.
Moving forward or down works great, but when you reach the third row it will take you up to the first cell instead of the second cell if your focus is on a div (compare to an input where it actually works).
The next problem is that if you press ALT+left arrow it will take you back to the first cell, when you should move to the previous cell.

Does it have anything to do with the $new_field[0] ?

 function placeCaretAtEnd(el) { el.focus(); if (typeof window.getSelection != "undefined" && typeof document.createRange != "undefined") { var range = document.createRange(); range.selectNodeContents(el); range.collapse(false); var sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); } else if (typeof document.body.createTextRange != "undefined") { var textRange = document.body.createTextRange(); textRange.moveToElementText(el); textRange.collapse(false); textRange.select(); } } $(document).on('keydown', '.field', function(e) { // If arrow up / down if( (e.which == 38 || e.which == 40 || e.which == 37 || e.which == 39) && e.altKey ) { var $self = $(this); var $field = $self.closest('td.nav-field:visible'); var data_field = $field.attr('data-field'); var $row = $self.closest('tr'); if( e.which == 38 ) { var $target = $row.prevAll('tr:visible'); $new_field = $target.find('td.nav-field[data-field="' + data_field + '"]:visible .field'); } else if( e.which == 40 ) { var $target = $row.nextAll('tr:visible').eq(0); $new_field = $target.find('td.nav-field[data-field="' + data_field + '"]:visible .field'); } else if( e.which == 37 ) { var $target = $field.prevAll('td.nav-field:visible'); $new_field = $target.find('.field'); } else if( e.which == 39 ) { var $target = $field.nextAll('td.nav-field:visible').eq(0); $new_field = $target.find('.field'); } setTimeout(function() { if( $new_field.is('input') ) { $new_field.select(); } else if( $new_field.is('div[contenteditable]') ) { placeCaretAtEnd($new_field[0]); } else { $new_field.focus(); } }, 1); } });
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <table> <tr> <td data-field="1" class="nav-field"><input value="Input 1" class="field"></td> <td data-field="2" class="nav-field"><div contenteditable="true" class="field">Content Editable 1</div></td> <td data-field="3" class="nav-field" style="display: none;"><input value="Input 2" class="field"></td> <td data-field="4" class="nav-field"><div contenteditable="true" class="field">Content Editable 2</div></td> <td data-field="5" class="nav-field"><input value="Input 3" class="field"></td> <td data-field="6">Not Editable</td> </tr> <tr style="display: none;"> <td data-field="1" class="nav-field"><input value="Input 1" class="field"></td> <td data-field="2" class="nav-field"><div contenteditable="true" class="field">Content Editable 1</div></td> <td data-field="3" class="nav-field" style="display: none;"><input value="Input 2" class="field"></td> <td data-field="4" class="nav-field"><div contenteditable="true" class="field">Content Editable 2</div></td> <td data-field="5" class="nav-field"><input value="Input 3" class="field"></td> <td data-field="6">Not Editable</td> </tr> <tr> <td data-field="1" class="nav-field"><input value="Input 1" class="field"></td> <td data-field="2" class="nav-field"><div contenteditable="true" class="field">Content Editable 1</div></td> <td data-field="3" class="nav-field" style="display: none;" class="field"><input value="Input 2"></td> <td data-field="4" class="nav-field"><div contenteditable="true" class="field">Content Editable 2</div></td> <td data-field="5" class="nav-field"><input value="Input 3" class="field"></td> <td data-field="6">Not Editable</td> </tr> <tr> <td data-field="1" class="nav-field"><input value="Input 1" class="field"></td> <td data-field="2" class="nav-field"><div contenteditable="true" class="field">Content Editable 1</div></td> <td data-field="3" class="nav-field" style="display: none;" class="field"><input value="Input 2"></td> <td data-field="4" class="nav-field"><div contenteditable="true" class="field">Content Editable 2</div></td> <td data-field="5" class="nav-field"><input value="Input 3" class="field"></td> <td data-field="6">Not Editable</td> </tr> </table>

I do not see why I should make you a complete solution, so here is just an example of using native Javascript methods to handle your problem...

 const myTable = document.querySelector('#my-Table tbody') , nbRows = myTable.rows.length , nbCells = myTable.rows[0].cells.length , moving = { ArrowUp : p=>{ pr = (--pr +nbRows ) % nbRows } , ArrowLeft : p=>{ pc = (--pc +nbCells) % nbCells } , ArrowDown : p=>{ pr = ++pr % nbRows } , ArrowRight : p=>{ pc = ++pc % nbCells } } document.onkeydown=e=> { let currentPos = myTable.querySelector('.select') , evt = (e==null ? event:e) , pos = { r:currentPos.parentNode.rowIndex , c:currentPos.cellIndex } if ( evt.altKey && moving[evt.code] ) { moving[evt.code](pos) currentPos.classList.remove('select') myTable.rows[pos.r].cells[pos.c].classList.add('select') } }
 #my-Table { border-collapse: collapse; font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif; font-size: 14px; } #my-Table td { width:20px; text-align: center; border: 1px solid grey; padding: 2px 5px; white-space: nowrap; } .select { background-color: aqua }
 <p>ALt arrow key usage...</p> <table id="my-Table"> <tbody> <tr><td class='select'>a</td><td>b</td><td>c</td><td>d</td></tr> <tr><td>e</td><td>f</td><td>g</td><td>h</td></tr> <tr><td>i</td><td>j</td><td>k</td><td>l</td></tr> <tr><td>m</td><td>n</td><td>o</td><td>p</td></tr> <tr><td>q</td><td>r</td><td>s</td><td>t</td></tr> </tbody> </table>

It's not that I wanted to do it, but when a problem has entered my mind, I want to finish it.

move key is [alt] + [shift] + [arrow keys] because [alt] + [arrow keys] corresponding for window moves on my computer (LINUX)

 const myTable = document.querySelector('#my-Table tbody') , nbRows = myTable.rows.length , nbCells = myTable.rows[0].cells.length , movKey = { ArrowUp : p=>{ pr = (--pr +nbRows ) % nbRows } , ArrowLeft : p=>{ pc = (--pc +nbCells) % nbCells } , ArrowDown : p=>{ pr = ++pr % nbRows } , ArrowRight : p=>{ pc = ++pc % nbCells } } // get On Focus event on Table elements myTable .querySelectorAll('input, [contenteditable=true]') .forEach(elm=>{elm.onfocus=e=> { let sPos = myTable.querySelector('.select') , tdPos = elm.parentNode if (sPos) sPos.classList.remove('select') tdPos.classList.add('select') } }) document.onkeydown=e=> { let sPos = myTable.querySelector('.select') , evt = (e==null ? event:e) , pos = { r: sPos?sPos.parentNode.rowIndex:-1 , c: sPos?sPos.cellIndex:-1 } if ( sPos // previous pos focus exist... && evt.altKey && evt.shiftKey // addin shift to control && movKey[evt.code] ) // evt.ctrlKey... ? { let loop = true , nxFocus = null , cell = null do { movKey[evt.code](pos) cell = myTable.rows[pos.r].cells[pos.c] // possible <td> for new focus... nxFocus = cell.querySelector('input, [contenteditable=true]') // get focussable element of <td> if ( nxFocus && cell.style.display!=='none' && cell.parentNode.style.display!=='none') { nxFocus.focus() loop = false } } while (loop) } }
 #my-Table { border-collapse: collapse; font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif; font-size: 14px; } #my-Table td { min-width:20px; text-align: center; border: 1px solid grey; padding: 2px 5px; white-space: nowrap; } .select { background-color: aqua } /* just for the control, delete this line when commissioning the operation */
 <table id="my-Table"> <tbody> <tr> <td><input placeholder="r0, c0"></td> <td><div contenteditable="true">Content Editable 1 r0, c1</div></td> <td style="display: none;"><input placeholder="r0, c2"></td> <td><div contenteditable="true">Content Editable 2 r0, c3</div></td> <td><input placeholder="r0, c4"></td> <td>Not Editable</td> </tr> <tr style="display: none;"> <td><input placeholder="r1, c1"></td><td><div contenteditable=" true">Content Editable 1</div></td> <td style="display: none;"><input value="Input 2"></td> <td><div contenteditable="true">Content Editable 2</div></td> <td><input value="Input 3"></td> <td>Not Editable</td> </tr> <tr> <td><input placeholder="r2, c0"></td> <td><div contenteditable="true">Content Editable 1</div></td> <td style="display: none;"><input value="Input 2"></td> <td><div contenteditable="true">Content Editable 2</div></td> <td><input value="Input 3"></td> <td>Not Editable</td> </tr> <tr> <td><input value="Input 1"></td> <td><div contenteditable="true">Content Editable 1</div></td> <td style="display: none;"><input value="Input 2"></td> <td><div contenteditable="true">Content Editable 2</div></td> <td><input value="Input 3"></td> <td>Not Editable</td> </tr> </tbody> </table>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM