需求描述
- 最近有一个需求,就是用户说,不习惯使用tab键做输入框input的光标切换
- (tab键盘没法回到之前的input光标,只能走了一圈后再回到原点那种)
- 用户喜欢使用上下左右键,来进行输入框切换
- 基于这个需求下,便有了本篇文章的示例
- 示例演示网站:http://ashuai.work:8890/30
- github:https://github.com/shuirongshuifu/vue3-echarts5-example
- 我们先看一下下方效果图:
需求效果图
需求思路
- 因为是通过上下左右键去控制,所以需要区分
event.key
为ArrowUp
或ArrowDown
或ArrowLeft
或ArrowRight
做对应逻辑控制 - 而后把对应的下一个输入框给
focus()且select()
- 即:
Input.focus()
和Input.select();
- 方然,也要
event.preventDefault();
- 在讲解代码之前,我们先来复习一下常用的input标签元素常用的方法
前置知识——Input元素常用方法
- 开发中常用的input实例的方法就是focus()和blur()比较多
- 实际上还有其他的方法,如:
Input.select()
选中输入框中所有的文本Input.setSelection(start, end)
选中输入框中部分文本start, end起始和结束位置Input.setRangeText(newText, start, end)
选中输入框中部分文本start, end起始和结束位置后,并做替换- 针对于数字输入框,使用
stepUp
或者stepDown
可以控制增加或者减少数字的值 - 此外,还有
checkValidity()、setCustomValidity()、reportValidity()
用于做输入框表单的校验 - 组件化开发中,用的不多,这三个了解即可
- 我们看一下下面的效果图:
Input效果图
select()
function selectInput() {
textInput.focus();
textInput.select();
result.textContent = "调用了 select() 方法 - 选中了文本输入框中的所有文本";
}
setSelectionRange()
function setSelection() {
textInput.focus();
if (textInput.value.length >= 7) {
textInput.setSelectionRange(3, 7);
result.textContent = "调用了 setSelectionRange(3,7) - 选中第3到第7个字符";
} else {
result.textContent = "文本太短,无法选择3-7位置";
}
}
setRangeText()
function setRangeText() {
textInput.focus();
if (textInput.value.length >= 7) {
textInput.setRangeText('新文本', 3, 7);
result.textContent = "调用了 setRangeText('新文本',3,7) - 替换了第3到第7个字符";
} else {
result.textContent = "文本太短,无法替换3-7位置";
}
}
stepUp()
function stepUpInput() {
numberInput.stepUp();
result.textContent = `调用了 stepUp() - 数值变为: ${numberInput.value}`;
}
function stepUpBy3() {
numberInput.stepUp(3);
result.textContent = `调用了 stepUp(3) - 数值变为: ${numberInput.value}`;
}
stepDown()
function stepDownInput() {
numberInput.stepDown();
result.textContent = `调用了 stepDown() - 数值变为: ${numberInput.value}`;
}
function stepDownBy3() {
numberInput.stepDown(3);
result.textContent = `调用了 stepDown(3) - 数值变为: ${numberInput.value}`;
}
完整代码
复制粘贴即用演示
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Input方法常用示例</title>
<style>
body {
width: 1000px;
margin: 0 auto;
}
.container {
display: flex;
flex-direction: column;
gap: 12px;
}
button {
padding: 8px 12px;
margin: 2px;
cursor: pointer;
}
.logArea {
margin-top: 20px;
padding: 12px;
border: 1px solid #ddd;
border-radius: 5px;
display: flex;
align-items: center;
}
.inputGroup {
margin: 8px 2px;
display: flex;
align-items: center;
}
</style>
</head>
<body>
<h2>Input元素常用方法演示</h2>
<div class="container">
<div class="inputGroup">
<div>文本输入框:</div>
<input type="text" id="textInput" value="这是一个示例文本">
</div>
<div class="inputGroup">
<div>数字输入框:</div>
<input type="number" id="numberInput" value="4" min="0" max="20" step="1">
</div>
<div>
<h4>文本操作方法:</h4>
<button onclick="focusInput()">focus()</button>
<button onclick="blurInput()">blur()</button>
<button onclick="selectInput()">select()</button>
<button onclick="setSelection()">setSelectionRange(3,7)</button>
<button onclick="setRangeText()">setRangeText('新文本',3,7)</button>
</div>
<div>
<h4>数字操作方法:</h4>
<button onclick="stepUpInput()">stepUp()</button>
<button onclick="stepDownInput()">stepDown()</button>
<button onclick="stepUpBy3()">stepUp(3)</button>
<button onclick="stepDownBy3()">stepDown(3)</button>
</div>
<div class="logArea">
<div>操作结果:</div>
<div id="result"></div>
</div>
</div>
<script>
const textInput = document.getElementById('textInput');
const numberInput = document.getElementById('numberInput');
const result = document.getElementById('result');
function focusInput() {
textInput.focus();
result.textContent = "调用了 focus() 方法 - 文本输入框获得焦点";
}
function blurInput() {
textInput.blur();
result.textContent = "调用了 blur() 方法 - 文本输入框失去焦点";
}
function selectInput() {
textInput.focus();
textInput.select();
result.textContent = "调用了 select() 方法 - 选中了文本输入框中的所有文本";
}
function setSelection() {
textInput.focus();
if (textInput.value.length >= 7) {
textInput.setSelectionRange(3, 7);
result.textContent = "调用了 setSelectionRange(3,7) - 选中第3到第7个字符";
} else {
result.textContent = "文本太短,无法选择3-7位置";
}
}
function setRangeText() {
textInput.focus();
if (textInput.value.length >= 7) {
textInput.setRangeText('新文本', 3, 7);
result.textContent = "调用了 setRangeText('新文本',3,7) - 替换了第3到第7个字符";
} else {
result.textContent = "文本太短,无法替换3-7位置";
}
}
function stepUpInput() {
numberInput.stepUp();
result.textContent = `调用了 stepUp() - 数值变为: ${numberInput.value}`;
}
function stepDownInput() {
numberInput.stepDown();
result.textContent = `调用了 stepDown() - 数值变为: ${numberInput.value}`;
}
function stepUpBy3() {
numberInput.stepUp(3);
result.textContent = `调用了 stepUp(3) - 数值变为: ${numberInput.value}`;
}
function stepDownBy3() {
numberInput.stepDown(3);
result.textContent = `调用了 stepDown(3) - 数值变为: ${numberInput.value}`;
}
</script>
</body>
</html>
方式一
html
<template>
<div class="box1">
<el-table :data="tableData" border style="width: 400px">
<el-table-column width="72px" prop="time" label="时间" align="center">
</el-table-column>
<el-table-column prop="dazhong" label="大众">
<template #default="scope">
<el-input @keydown="handleKeyDown(scope.$index, 0, $event)"
oninput="value=value.replace(/^\.+|[^\d.]/g,'')" maxlength="3"
v-model.trim="scope.row.dazhong" />
</template>
</el-table-column>
<el-table-column prop="tongyong" label="通用">
<template #default="scope">
<el-input @keydown="handleKeyDown(scope.$index, 1, $event)"
oninput="value=value.replace(/^\.+|[^\d.]/g,'')" maxlength="3"
v-model.trim="scope.row.tongyong" />
</template>
</el-table-column>
<el-table-column prop="jipu" label="吉普">
<template #default="scope">
<el-input @keydown="handleKeyDown(scope.$index, 2, $event)"
oninput="value=value.replace(/^\.+|[^\d.]/g,'')" maxlength="3" v-model.trim="scope.row.jipu" />
</template>
</el-table-column>
<el-table-column prop="fengtian" label="丰田">
<template #default="scope">
<el-input @keydown="handleKeyDown(scope.$index, 3, $event)"
oninput="value=value.replace(/^\.+|[^\d.]/g,'')" maxlength="3"
v-model.trim="scope.row.fengtian" />
</template>
</el-table-column>
</el-table>
</div>
</template>
- 注意,我们直接使用e就行了
- 即:
@keydown="handleKeyDown(scope.$index, 2, $event)"
- 这里需要手动指定列的索引,比如上述的
2
。行的索引直接使用scope.$index
即可 - 后续就是通过行列的索引,来获取下一个输入框并聚焦和选中文本
表格模拟数据
const tableData = ref([
{
time: "第一组",
dazhong: 1,
tongyong: 2,
jipu: 3,
fengtian: 4,
},
{
time: "第二组",
dazhong: 5,
tongyong: 6,
jipu: 7,
fengtian: 8,
},
{
time: "第三组",
dazhong: 9,
tongyong: 10,
jipu: 11,
fengtian: 12,
},
{
time: "第四组",
dazhong: 13,
tongyong: 14,
jipu: 15,
fengtian: 16,
},
]);
关键控制代码
const handleKeyDown = (rowIndex, colIndex, event) => {
const key = event.key;
let nextRow = rowIndex;
let nextCol = colIndex;
if (key === "ArrowUp") {
nextRow = Math.max(0, rowIndex - 1);
} else if (key === "ArrowDown") {
nextRow = Math.min(tableData.value.length - 1, rowIndex + 1);
} else if (key === "ArrowLeft") {
nextCol = Math.max(0, colIndex - 1);
} else if (key === "ArrowRight") {
nextCol = Math.min(3, colIndex + 1);
} else {
return;
}
event.preventDefault();
// 获取下一个输入框并聚焦和选中文本
const nextInput = document.querySelectorAll(".box1 .el-input__inner")[nextRow * 4 + nextCol];
if (nextInput) {
nextInput.focus();
nextInput.select();
}
};
方式二的js逻辑
- html不变,js思路都是一样的
- 基于此,实际上可以扩展n行n列(上文是4行4列)
const columnCount = 4; // 数据列的数量
const handleKeyDown = (rowIndex, colIndex, event) => {
const key = event.key;
let nextRow = rowIndex;
let nextCol = colIndex;
if (key === "ArrowUp") {
if (rowIndex === 0) {
nextRow = tableData.value.length - 1;
} else {
nextRow = rowIndex - 1;
}
} else if (key === "ArrowDown") {
if (rowIndex === tableData.value.length - 1) {
nextRow = 0;
} else {
nextRow = rowIndex + 1;
}
} else if (key === "ArrowLeft") {
if (colIndex === 0) {
if (rowIndex === 0) {
nextRow = tableData.value.length - 1;
nextCol = columnCount - 1;
} else {
nextRow = rowIndex - 1;
nextCol = columnCount - 1;
}
} else {
nextCol = colIndex - 1;
}
} else if (key === "ArrowRight") {
if (colIndex === columnCount - 1) {
if (rowIndex === tableData.value.length - 1) {
nextRow = 0;
nextCol = 0;
} else {
nextRow = rowIndex + 1;
nextCol = 0;
}
} else {
nextCol = colIndex + 1;
}
} else {
return;
}
event.preventDefault();
// 获取下一个输入框并聚焦和选中文本
const nextInput = document.querySelectorAll(".box2 .el-input__inner")[
nextRow * columnCount + nextCol
];
if (nextInput) {
nextInput.focus();
nextInput.select();
}
};
A good memory is not as good as a bad pen...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。