首页 > 解决方案 > 如何将焦点更改为表格单元格中的下一个或上一个可聚焦和启用的输入(仅限 jQuery 或 vanilla javascript)?

问题描述

在 HTML 表格中,合理数量的单元格,跨越多行,包括可能启用或不启用的文本输入,具体取决于下拉列表中先前选择的选项。虽然 tabindex 已正确配置,以便用户可以使用 TAB 或 SHIFT+TAB 在这些输入之间导航,但我被要求使用 LEFT 和 RIGHT 箭头键复制此行为,事实证明这很难实现。

HTML 的简化版本:

<html><body>
  <table><tr>
    <th></th>
    <th>Sample<br/>01</th>
    <th>Sample<br/>02</th>
    <th>Sample<br/>03</th>
    <th>Sample<br/>04</th>
    <th>Sample<br/>05</th>
  </tr><tr>
    <th>Group 01</th>
    <td>
      <input type="text" tabindex="1" class="sample-value" 
             name="edtG01S01" id="edtG01S01"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG01S01" id="cbxG01S01"/> &lt;1
    </td>
    <td>
      <input type="text" tabindex="2" class="sample-value" 
             name="edtG01S02" id="edtG01S02"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG01S02" id="cbxG01S02"/> &lt;1
    </td>
    <td>
      <input type="text" tabindex="3" class="sample-value" 
             name="edtG01S03" id="edtG01S03" disabled="disabled"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG01S03" id="cbxG01S03"/> &lt;1
    </td>
    <td>
      <input type="text" tabindex="4" class="sample-value" 
             name="edtG01S04" id="edtG01S04"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG01S04" id="cbxG01S04"/> &lt;1
    </td>
    <td>
      <input type="text" tabindex="5" class="sample-value" 
             name="edtG01S05" id="edtG01S05"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG01S05" id="cbxG01S05"/> &lt;1
    </td>
  </tr><tr>
    <th>Group 02</th>
    <td>
      <input type="text" tabindex="6" class="sample-value" 
             name="edtG02S01" id="edtG02S01"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG02S01" id="cbxG02S01"/> &lt;1
    </td>
    <td>
      <input type="text" tabindex="7" class="sample-value" 
             name="edtG02S02" id="edtG02S02"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG02S02" id="cbxG02S02"/> &lt;1
    </td>
    <td>
      <input type="text" tabindex="8" class="sample-value" 
             name="edtG02S03" id="edtG02S03" disabled="disabled"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG02S03" id="cbxG02S03"/> &lt;1
    </td>
    <td>
      <input type="text" tabindex="9" class="sample-value" 
             name="edtG02S04" id="edtG01S04"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG02S04" id="cbxG02S04"/> &lt;1
    </td>
    <td>
      <input type="text" tabindex="10" class="sample-value" 
             name="edtG02S05" id="edtG02S05"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG02S05" id="cbxG02S05"/> &lt;1
    </td>
  </tr></table>
</body></html>

输入有 class sample-value,目前我最接近的工作是:

$('input.sample-value').keyup(function(event) {
  if (event.which == 39) { /* right arrow key */
    $(this).parent('td').next('td').find('input.sample-value').focus();
    event.preventDefault();
  }
  if (event.which == 37) { /* left arrow key */
    $(this).parent('td').prev('td').find('input.sample-value').focus();
    event.preventDefault();
  }
});

使用上面的代码,左右箭头键可以按预期在输入之间导航,直到您到达禁用的输入,或者直到您到达一行的末尾。此时,它无法向前或向后跳到下一个可聚焦输入。

有没有一种方法可以使这段代码足够灵活,以导航到适当的input.sample-value元素,而不管它位于表格行或列中的什么位置,并且能够考虑跳过禁用的输入?输入在页面加载时不会被禁用,而是动态启用或禁用以响应在这些输入之前的下拉列表中选择的选项。

完整的工作示例:

$('input.sample-value').keyup(function(event) {
  if (event.which == 39) { /* right arrow key */
    $(this).parent('td').next('td').find('input.sample-value').focus();
    event.preventDefault();
  }
  if (event.which == 37) { /* left arrow key */
    $(this).parent('td').prev('td').find('input.sample-value').focus();
    event.preventDefault();
  }
});
* {
  font-family: Arial;
}
input.sample-value {
  width: 50px;
}
th, td {
  padding: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html><body>
  <table><tr>
    <th></th>
    <th>Sample<br/>01</th>
    <th>Sample<br/>02</th>
    <th>Sample<br/>03</th>
    <th>Sample<br/>04</th>
    <th>Sample<br/>05</th>
  </tr><tr>
    <th>Group 01</th>
    <td>
      <input type="text" tabindex="1" class="sample-value" 
             name="edtG01S01" id="edtG01S01"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG01S01" id="cbxG01S01"/> &lt;1
    </td>
    <td>
      <input type="text" tabindex="2" class="sample-value" 
             name="edtG01S02" id="edtG01S02"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG01S02" id="cbxG01S02"/> &lt;1
    </td>
    <td>
      <input type="text" tabindex="3" class="sample-value" 
             name="edtG01S03" id="edtG01S03" disabled="disabled"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG01S03" id="cbxG01S03"/> &lt;1
    </td>
    <td>
      <input type="text" tabindex="4" class="sample-value" 
             name="edtG01S04" id="edtG01S04"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG01S04" id="cbxG01S04"/> &lt;1
    </td>
    <td>
      <input type="text" tabindex="5" class="sample-value" 
             name="edtG01S05" id="edtG01S05"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG01S05" id="cbxG01S05"/> &lt;1
    </td>
  </tr><tr>
    <th>Group 02</th>
    <td>
      <input type="text" tabindex="6" class="sample-value" 
             name="edtG02S01" id="edtG02S01"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG02S01" id="cbxG02S01"/> &lt;1
    </td>
    <td>
      <input type="text" tabindex="7" class="sample-value" 
             name="edtG02S02" id="edtG02S02"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG02S02" id="cbxG02S02"/> &lt;1
    </td>
    <td>
      <input type="text" tabindex="8" class="sample-value" 
             name="edtG02S03" id="edtG02S03" disabled="disabled"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG02S03" id="cbxG02S03"/> &lt;1
    </td>
    <td>
      <input type="text" tabindex="9" class="sample-value" 
             name="edtG02S04" id="edtG01S04"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG02S04" id="cbxG02S04"/> &lt;1
    </td>
    <td>
      <input type="text" tabindex="10" class="sample-value" 
             name="edtG02S05" id="edtG02S05"/>
      <br/>
      <input type="checkbox" tabindex="-1" name="cbxG02S05" id="cbxG02S05"/> &lt;1
    </td>
  </tr></table>
</body></html>

也可用作 JSFiddle:https ://jsfiddle.net/zoLwv5d9/

标签: javascriptjquery

解决方案


我对您的代码进行了一些更改,因此它现在跳过禁用的输入并在到达结束或开始时跳转到第一个/最后一个。

var next = $(this).parent('td').next('td');

if (next.length == 0) {
  next = $(this).closest("tr").find("td:first")
} else if (next.find("input:disabled").length > 0) {
  next = next.next("td")
}

next.find('input.sample-value').focus();
event.preventDefault();

演示

$('input.sample-value').keyup(function(event) {
  if (event.which == 39) { /* right arrow key */
    var next = $(this).parent('td').next('td');

    if (next.length == 0) {
      next = $(this).closest("tr").find("td:first")
    } else if (next.find("input:disabled").length > 0) {
      next = next.next("td")
    }

    next.find('input.sample-value').focus();
    event.preventDefault();
  }
  if (event.which == 37) { /* left arrow key */
    var prev = $(this).parent('td').prev('td');

    if (prev.length == 0) {
      prev = $(this).closest("tr").find("td:last")
    } else if (prev.find("input:disabled").length > 0) {
      prev = prev.prev("td")
    }

    prev.find('input.sample-value').focus();
    event.preventDefault();
  }
});
* {
  font-family: Arial;
}

input.sample-value {
  width: 50px;
}

th,
td {
  padding: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>

<body>
  <table>
    <tr>
      <th></th>
      <th>Sample<br/>01</th>
      <th>Sample<br/>02</th>
      <th>Sample<br/>03</th>
      <th>Sample<br/>04</th>
      <th>Sample<br/>05</th>
    </tr>
    <tr>
      <th>Group 01</th>
      <td>
        <input type="text" tabindex="1" class="sample-value" name="edtG01S01" id="edtG01S01" />
        <br/>
        <input type="checkbox" tabindex="-1" name="cbxG01S01" id="cbxG01S01" /> &lt;1
      </td>
      <td>
        <input type="text" tabindex="2" class="sample-value" name="edtG01S02" id="edtG01S02" />
        <br/>
        <input type="checkbox" tabindex="-1" name="cbxG01S02" id="cbxG01S02" /> &lt;1
      </td>
      <td>
        <input type="text" tabindex="3" class="sample-value" name="edtG01S03" id="edtG01S03" disabled="disabled" />
        <br/>
        <input type="checkbox" tabindex="-1" name="cbxG01S03" id="cbxG01S03" /> &lt;1
      </td>
      <td>
        <input type="text" tabindex="4" class="sample-value" name="edtG01S04" id="edtG01S04" />
        <br/>
        <input type="checkbox" tabindex="-1" name="cbxG01S04" id="cbxG01S04" /> &lt;1
      </td>
      <td>
        <input type="text" tabindex="5" class="sample-value" name="edtG01S05" id="edtG01S05" />
        <br/>
        <input type="checkbox" tabindex="-1" name="cbxG01S05" id="cbxG01S05" /> &lt;1
      </td>
    </tr>
    <tr>
      <th>Group 02</th>
      <td>
        <input type="text" tabindex="6" class="sample-value" name="edtG02S01" id="edtG02S01" />
        <br/>
        <input type="checkbox" tabindex="-1" name="cbxG02S01" id="cbxG02S01" /> &lt;1
      </td>
      <td>
        <input type="text" tabindex="7" class="sample-value" name="edtG02S02" id="edtG02S02" />
        <br/>
        <input type="checkbox" tabindex="-1" name="cbxG02S02" id="cbxG02S02" /> &lt;1
      </td>
      <td>
        <input type="text" tabindex="8" class="sample-value" name="edtG02S03" id="edtG02S03" disabled="disabled" />
        <br/>
        <input type="checkbox" tabindex="-1" name="cbxG02S03" id="cbxG02S03" /> &lt;1
      </td>
      <td>
        <input type="text" tabindex="9" class="sample-value" name="edtG02S04" id="edtG01S04" />
        <br/>
        <input type="checkbox" tabindex="-1" name="cbxG02S04" id="cbxG02S04" /> &lt;1
      </td>
      <td>
        <input type="text" tabindex="10" class="sample-value" name="edtG02S05" id="edtG02S05" />
        <br/>
        <input type="checkbox" tabindex="-1" name="cbxG02S05" id="cbxG02S05" /> &lt;1
      </td>
    </tr>
  </table>
</body>

</html>


推荐阅读