使用箭头键导航HTML表

时间:2022-09-11 17:09:50

I've created a very basic spreadsheet using an HTML table. It works perfectly, except the user must use the mouse to click on every <td> in order to edit it. I'm capturing the click event with jQuery and displaying a dialog to edit it. I would like the user to be able to use the arrow keys to navigate to each cell, with the cell css background changing to indicate focus, and clicking the Enter key would trigger the jQuery dialog event. I'm using jQuery 1.9.

我使用HTML表格创建了一个非常基本的电子表格。它工作的很好,除了用户必须使用鼠标点击每一个,以便编辑它。我用jQuery捕获单击事件并显示一个对话框来编辑它。我希望用户能够使用箭头键导航到每个单元,单元格css背景改变为表示焦点,单击Enter键将触发jQuery对话框事件。我使用jQuery 1.9。

Here is a jsfiddle of basically what I have.

这是一个简单的例子。

How do you save the currently selected cell, so that when you click on a cell with the mouse, and then use the arrow keys, it will navigate from the 'current' cell?

如何保存当前选定的单元格,以便当您使用鼠标单击单元格,然后使用箭头键时,它将从“当前”单元格中导航?

Thanks.

谢谢。

2 个解决方案

#1


8  

Below is a vanilla JavaScript solution using the onkeydown event and using the previousElementSibling and nextElementSibling properties.

下面是一个普通的JavaScript解决方案,使用onkeydown事件和previousElementSibling和nextElementSibling属性。

https://jsfiddle.net/rh5aoxsL/

https://jsfiddle.net/rh5aoxsL/

The problem with using tabindex is that you dont get to navigate the way you would in Excel and you can navigate away from the spreadsheet itself.

使用tabindex的问题在于,你不能像在Excel中那样导航,而可以从电子表格本身中导航。

The HTML

HTML

<table>
  <tbody>
    <tr>
      <td id='start'>1</td>
      <td>2</td>
      <td>3</td>
      <td>4</td>
    </tr>
    <tr>
      <td>5</td>
      <td>6</td>
      <td>7</td>
      <td>8</td>
    </tr>
    <tr>
      <td>9</td>
      <td>10</td>
      <td>11</td>
      <td>12</td>
    </tr>
    <tr>
      <td>13</td>
      <td>14</td>
      <td>15</td>
      <td>16</td>
    </tr>
  </tbody>
</table>

The CSS

CSS

table {
  border-collapse: collapse;
  border: 1px solid black;
}
table td {
  border: 1px solid black;
  padding: 10px;
  text-align: center;
}

The JavaScript

JavaScript

var start = document.getElementById('start');
start.focus();
start.style.backgroundColor = 'green';
start.style.color = 'white';

function dotheneedful(sibling) {
  if (sibling != null) {
    start.focus();
    start.style.backgroundColor = '';
    start.style.color = '';
    sibling.focus();
    sibling.style.backgroundColor = 'green';
    sibling.style.color = 'white';
    start = sibling;
  }
}

document.onkeydown = checkKey;

function checkKey(e) {
  e = e || window.event;
  if (e.keyCode == '38') {
    // up arrow
    var idx = start.cellIndex;
    var nextrow = start.parentElement.previousElementSibling;
    if (nextrow != null) {
      var sibling = nextrow.cells[idx];
      dotheneedful(sibling);
    }
  } else if (e.keyCode == '40') {
    // down arrow
    var idx = start.cellIndex;
    var nextrow = start.parentElement.nextElementSibling;
    if (nextrow != null) {
      var sibling = nextrow.cells[idx];
      dotheneedful(sibling);
    }
  } else if (e.keyCode == '37') {
    // left arrow
    var sibling = start.previousElementSibling;
    dotheneedful(sibling);
  } else if (e.keyCode == '39') {
    // right arrow
    var sibling = start.nextElementSibling;
    dotheneedful(sibling);
  }
}

#2


5  

I figured it out, based on information I found on a few other posts. I rolled it all together, and the results are perfect.

根据我在其他几篇文章中找到的信息,我找到了答案。我把它们都卷在一起,结果是完美的。

Note: You have to put a tabindex attribute on every <td> to allow navigation.

注意:您必须在每一个上放置一个tabindex属性来允许导航。

Here's the jsfiddle. The same code is broken out below.

这是jsfiddle。下面列出了相同的代码。

The HTML:

HTML:

<table>
    <thead>
        <tr>
            <th>Col 1</th>
            <th>Col 2</th>
            <th>Col 3</th>
            <th>Col 4</th>
            <th>Col 5</th>
            <th>Col 6</th>
            <th>Col 7</th>
            <th>Col 8</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td tabindex="1">1</td>
            <td tabindex="2">2</td>
            <td tabindex="3">3</td>
            <td tabindex="4">4</td>
            <td tabindex="5">5</td>
            <td tabindex="6">6</td>
            <td tabindex="7">7</td>
            <td tabindex="8">8</td>
        </tr>
        <tr>
            <td tabindex="10">10</td>
            <td tabindex="11">11</td>
            <td tabindex="12">12</td>
            <td tabindex="13">13</td>
            <td tabindex="14">14</td>
            <td tabindex="15">15</td>
            <td tabindex="16">16</td>
            <td tabindex="17">17</td>
        </tr>
    </tbody>
</table>

<div id="edit">
    <form>
        <input type="text" id="text" value="To edit..." />
        <input type="submit" value="Save" />
    </form>
</div>

The CSS:

CSS:

* {
    font-size: 12px;
    font-family: 'Helvetica', Arial, Sans-Serif;
    box-sizing: border-box;
}

table, th, td {
    border-collapse:collapse;
    border: solid 1px #ccc;
    padding: 10px 20px;
    text-align: center;
}

th {
    background: #0f4871;
    color: #fff;
}

tr:nth-child(2n) {
    background: #f1f1f1;
}
td:hover {
    color: #fff;
    background: #CA293E;
}
td:focus {
    background: #f44;
}

.editing {
    border: 2px dotted #c9c9c9;
}

#edit { 
    display: none;
}

The jQuery:

jQuery:

var currCell = $('td').first();
var editing = false;

// User clicks on a cell
$('td').click(function() {
    currCell = $(this);
    edit();
});

// Show edit box
function edit() {
    editing = true;
    currCell.toggleClass("editing");
    $('#edit').show();
    $('#edit #text').val(currCell.html());
    $('#edit #text').select();
}

// User saves edits
$('#edit form').submit(function(e) {
    editing = false;
    e.preventDefault();
    // Ajax to update value in database
    $.get('#', '', function() {
        $('#edit').hide();
        currCell.toggleClass("editing");
        currCell.html($('#edit #text').val());
        currCell.focus();
    });
});

// User navigates table using keyboard
$('table').keydown(function (e) {
    var c = "";
    if (e.which == 39) {
        // Right Arrow
        c = currCell.next();
    } else if (e.which == 37) { 
        // Left Arrow
        c = currCell.prev();
    } else if (e.which == 38) { 
        // Up Arrow
        c = currCell.closest('tr').prev().find('td:eq(' + 
          currCell.index() + ')');
    } else if (e.which == 40) { 
        // Down Arrow
        c = currCell.closest('tr').next().find('td:eq(' + 
          currCell.index() + ')');
    } else if (!editing && (e.which == 13 || e.which == 32)) { 
        // Enter or Spacebar - edit cell
        e.preventDefault();
        edit();
    } else if (!editing && (e.which == 9 && !e.shiftKey)) { 
        // Tab
        e.preventDefault();
        c = currCell.next();
    } else if (!editing && (e.which == 9 && e.shiftKey)) { 
        // Shift + Tab
        e.preventDefault();
        c = currCell.prev();
    } 

    // If we didn't hit a boundary, update the current cell
    if (c.length > 0) {
        currCell = c;
        currCell.focus();
    }
});

// User can cancel edit by pressing escape
$('#edit').keydown(function (e) {
    if (editing && e.which == 27) { 
        editing = false;
        $('#edit').hide();
        currCell.toggleClass("editing");
        currCell.focus();
    }
});

#1


8  

Below is a vanilla JavaScript solution using the onkeydown event and using the previousElementSibling and nextElementSibling properties.

下面是一个普通的JavaScript解决方案,使用onkeydown事件和previousElementSibling和nextElementSibling属性。

https://jsfiddle.net/rh5aoxsL/

https://jsfiddle.net/rh5aoxsL/

The problem with using tabindex is that you dont get to navigate the way you would in Excel and you can navigate away from the spreadsheet itself.

使用tabindex的问题在于,你不能像在Excel中那样导航,而可以从电子表格本身中导航。

The HTML

HTML

<table>
  <tbody>
    <tr>
      <td id='start'>1</td>
      <td>2</td>
      <td>3</td>
      <td>4</td>
    </tr>
    <tr>
      <td>5</td>
      <td>6</td>
      <td>7</td>
      <td>8</td>
    </tr>
    <tr>
      <td>9</td>
      <td>10</td>
      <td>11</td>
      <td>12</td>
    </tr>
    <tr>
      <td>13</td>
      <td>14</td>
      <td>15</td>
      <td>16</td>
    </tr>
  </tbody>
</table>

The CSS

CSS

table {
  border-collapse: collapse;
  border: 1px solid black;
}
table td {
  border: 1px solid black;
  padding: 10px;
  text-align: center;
}

The JavaScript

JavaScript

var start = document.getElementById('start');
start.focus();
start.style.backgroundColor = 'green';
start.style.color = 'white';

function dotheneedful(sibling) {
  if (sibling != null) {
    start.focus();
    start.style.backgroundColor = '';
    start.style.color = '';
    sibling.focus();
    sibling.style.backgroundColor = 'green';
    sibling.style.color = 'white';
    start = sibling;
  }
}

document.onkeydown = checkKey;

function checkKey(e) {
  e = e || window.event;
  if (e.keyCode == '38') {
    // up arrow
    var idx = start.cellIndex;
    var nextrow = start.parentElement.previousElementSibling;
    if (nextrow != null) {
      var sibling = nextrow.cells[idx];
      dotheneedful(sibling);
    }
  } else if (e.keyCode == '40') {
    // down arrow
    var idx = start.cellIndex;
    var nextrow = start.parentElement.nextElementSibling;
    if (nextrow != null) {
      var sibling = nextrow.cells[idx];
      dotheneedful(sibling);
    }
  } else if (e.keyCode == '37') {
    // left arrow
    var sibling = start.previousElementSibling;
    dotheneedful(sibling);
  } else if (e.keyCode == '39') {
    // right arrow
    var sibling = start.nextElementSibling;
    dotheneedful(sibling);
  }
}

#2


5  

I figured it out, based on information I found on a few other posts. I rolled it all together, and the results are perfect.

根据我在其他几篇文章中找到的信息,我找到了答案。我把它们都卷在一起,结果是完美的。

Note: You have to put a tabindex attribute on every <td> to allow navigation.

注意:您必须在每一个上放置一个tabindex属性来允许导航。

Here's the jsfiddle. The same code is broken out below.

这是jsfiddle。下面列出了相同的代码。

The HTML:

HTML:

<table>
    <thead>
        <tr>
            <th>Col 1</th>
            <th>Col 2</th>
            <th>Col 3</th>
            <th>Col 4</th>
            <th>Col 5</th>
            <th>Col 6</th>
            <th>Col 7</th>
            <th>Col 8</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td tabindex="1">1</td>
            <td tabindex="2">2</td>
            <td tabindex="3">3</td>
            <td tabindex="4">4</td>
            <td tabindex="5">5</td>
            <td tabindex="6">6</td>
            <td tabindex="7">7</td>
            <td tabindex="8">8</td>
        </tr>
        <tr>
            <td tabindex="10">10</td>
            <td tabindex="11">11</td>
            <td tabindex="12">12</td>
            <td tabindex="13">13</td>
            <td tabindex="14">14</td>
            <td tabindex="15">15</td>
            <td tabindex="16">16</td>
            <td tabindex="17">17</td>
        </tr>
    </tbody>
</table>

<div id="edit">
    <form>
        <input type="text" id="text" value="To edit..." />
        <input type="submit" value="Save" />
    </form>
</div>

The CSS:

CSS:

* {
    font-size: 12px;
    font-family: 'Helvetica', Arial, Sans-Serif;
    box-sizing: border-box;
}

table, th, td {
    border-collapse:collapse;
    border: solid 1px #ccc;
    padding: 10px 20px;
    text-align: center;
}

th {
    background: #0f4871;
    color: #fff;
}

tr:nth-child(2n) {
    background: #f1f1f1;
}
td:hover {
    color: #fff;
    background: #CA293E;
}
td:focus {
    background: #f44;
}

.editing {
    border: 2px dotted #c9c9c9;
}

#edit { 
    display: none;
}

The jQuery:

jQuery:

var currCell = $('td').first();
var editing = false;

// User clicks on a cell
$('td').click(function() {
    currCell = $(this);
    edit();
});

// Show edit box
function edit() {
    editing = true;
    currCell.toggleClass("editing");
    $('#edit').show();
    $('#edit #text').val(currCell.html());
    $('#edit #text').select();
}

// User saves edits
$('#edit form').submit(function(e) {
    editing = false;
    e.preventDefault();
    // Ajax to update value in database
    $.get('#', '', function() {
        $('#edit').hide();
        currCell.toggleClass("editing");
        currCell.html($('#edit #text').val());
        currCell.focus();
    });
});

// User navigates table using keyboard
$('table').keydown(function (e) {
    var c = "";
    if (e.which == 39) {
        // Right Arrow
        c = currCell.next();
    } else if (e.which == 37) { 
        // Left Arrow
        c = currCell.prev();
    } else if (e.which == 38) { 
        // Up Arrow
        c = currCell.closest('tr').prev().find('td:eq(' + 
          currCell.index() + ')');
    } else if (e.which == 40) { 
        // Down Arrow
        c = currCell.closest('tr').next().find('td:eq(' + 
          currCell.index() + ')');
    } else if (!editing && (e.which == 13 || e.which == 32)) { 
        // Enter or Spacebar - edit cell
        e.preventDefault();
        edit();
    } else if (!editing && (e.which == 9 && !e.shiftKey)) { 
        // Tab
        e.preventDefault();
        c = currCell.next();
    } else if (!editing && (e.which == 9 && e.shiftKey)) { 
        // Shift + Tab
        e.preventDefault();
        c = currCell.prev();
    } 

    // If we didn't hit a boundary, update the current cell
    if (c.length > 0) {
        currCell = c;
        currCell.focus();
    }
});

// User can cancel edit by pressing escape
$('#edit').keydown(function (e) {
    if (editing && e.which == 27) { 
        editing = false;
        $('#edit').hide();
        currCell.toggleClass("editing");
        currCell.focus();
    }
});