博客 / 詳情

返回

實現el-table中輸入框單元格的上下左右鍵快捷切換

需求描述

  • 最近有一個需求,就是用户説,不習慣使用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...
user avatar shijuepaipie 頭像 qzmly 頭像 fish_head 頭像
3 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.