需求描述

  • 最近有一个需求,就是用户说,不习惯使用tab键做输入框input的光标切换
  • (tab键盘没法回到之前的input光标,只能走了一圈后再回到原点那种)
  • 用户喜欢使用上下左右键,来进行输入框切换
  • 基于这个需求下,便有了本篇文章的示例
  • 示例演示网站:http://ashuai.work:8890/30
  • github:https://github.com/shuirongshuifu/vue3-echarts5-example
  • 我们先看一下下方效果图:

需求效果图

需求思路

  • 因为是通过上下左右键去控制,所以需要区分event.keyArrowUpArrowDownArrowLeftArrowRight做对应逻辑控制
  • 而后把对应的下一个输入框给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>&nbsp;
            <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...

水冗水孚
1.1k 声望597 粉丝

每一个不曾起舞的日子,都是对生命的辜负