JS 手写 虚拟键盘

297 阅读2分钟

Snipaste_2023-07-13_15-48-51.png

虚拟键盘的主要核心点——输入的前提是:必须记录存在焦点的东西,有焦点可以输入,没有就不行

  1. 基本的html结构
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Virtual keyboard</title>
    <style>
        #virtualKeyboard {
            width: 600px;
        }

        .row {
            display: flex;
        }

        .key {
            width: 40px;
            height: 40px;
            background-color: #ccc;
            display: flex;
            justify-content: center;
            align-items: center;
            margin: 2px;
        }

        .key-auto {
            flex: auto;
        }

        input:focus,textarea:focus {
            border: 1px solid red;
            background-color:yellow;
        }
        
    </style>
</head>

<body>
 <!-- 键盘 -->
    <div id="virtualKeyboard">
        <div class="row">
            <button class="key key-f">`</button>
            <button class="key key-f">1</button>
            <button class="key key-f">2</button>
            <button class="key key-f">3</button>
            <button class="key key-f">4</button>
            <button class="key key-f">5</button>
            <button class="key key-f">6</button>
            <button class="key key-f">7</button>
            <button class="key key-f">8</button>
            <button class="key key-f">9</button>
            <button class="key key-f">0</button>
            <button class="key key-f">-</button>
            <button class="key key-f">=</button>
            <button class="key key-auto">Del</button>
        </div>
        <div class="row">
            <button class="key key-auto">Tab</button>
            <button class="key key-u">q</button>
            <button class="key key-u">w</button>
            <button class="key key-u">e</button>
            <button class="key key-u">r</button>
            <button class="key key-u">t</button>
            <button class="key key-u">y</button>
            <button class="key key-u">u</button>
            <button class="key key-u">i</button>
            <button class="key key-u">o</button>
            <button class="key key-u">p</button>
            <button class="key key-f">[</button>
            <button class="key key-f">]</button>
            <button class="key key-f">\</button>
        </div>
        <div class="row">
            <button class="key key-auto">Caps</button>
            <button class="key key-u">a</button>
            <button class="key key-u">s</button>
            <button class="key key-u">d</button>
            <button class="key key-u">f</button>
            <button class="key key-u">g</button>
            <button class="key key-u">h</button>
            <button class="key key-u">j</button>
            <button class="key key-u">k</button>
            <button class="key key-u">l</button>
            <button class="key key-f">;</button>
            <button class="key key-f">'</button>
            <button class="key key-auto">Enter</button>
        </div>
        <div class="row">
            <button class="key key-auto key-shift">Shift</button>
            <button class="key key-u">z</button>
            <button class="key key-u">x</button>
            <button class="key key-u">c</button>
            <button class="key key-u">v</button>
            <button class="key key-u">b</button>
            <button class="key key-u">h</button>
            <button class="key key-u">n</button>
            <button class="key key-u">m</button>
            <button class="key key-f">,</button>
            <button class="key key-f">.</button>
            <button class="key key-f">/</button>
            <button class="key key-auto">Shift</button>
        </div>
        <div class="row">
            <button class="key key-auto">Space</button>
        </div>
    </div>

<!-- 页面上的input 、textarea -->
    <br />
    <input type="text" />
    <br /><br />
    <input type="text" />
    <br /><br />
    <input type="text" />
    <br /><br />
    <input type="text" />
    <br /><br />
    <textarea num="" id="" cols="30" rows="10"></textarea>
    <br /><br />
    <textarea num="" id="" cols="30" rows="10"></textarea>
    <br /><br />
</body>

</html>
  1. 记录存在焦点的东西,有焦点可以输入,没有就不行。

(1)inputTextareaEle: 获取页面上所有的 input 、textarea;

自定义变量isKeyClick判断 input 、textarea 是否在焦点,

        const inputTextareaEle = document.querySelectorAll("input, textarea");
        let isKeyClick = false;

(2)页面上所有的 input 、textarea 添加 失去焦点事件监听器,

当元素失去焦点时,会检查 isKeyClick 变量的值,如果为 true,则使用 ele.focus() 将焦点重新设置到当前元素上。

        inputTextareaEle.forEach( (ele, eleNum) => {
            ele.addEventListener('blur', e => {
                if(isKeyClick) ele.focus()
            })
        })

(3)给每一个虚拟按键添加mousedown鼠标事件,并 当 按下 虚拟按键 时 把isKeyClick 的值赋值为true,触发innerCont函数,并把被点击元素的文本内容传递过去。

        document.addEventListener('mousedown', (e) => {
            if(e.target.className.includes('key')) {
                isKeyClick = true;
                let keyVal = e.target.textContent;
                innerCont(keyVal)
            } else {
                isKeyClick = false
            }
        })

(4)innerCont函数: 修改 页面上的 input 、textarea 的 value 值

document.activeElement:获取当前拥有焦点(即处于活动状态)的元素;

document.activeElement.selectionStart: 获取当前具有焦点的文本输入元素(如 <input><textarea>)中所选文本的起始位置的属性;

document.activeElement.selectionEnd 是用于获取当前具有焦点的文本输入元素(如 <input><textarea>)中所选文本的结束位置的属性。

最后:更新文本输入元素中的值(adom.value) = 从起始位置之前的部分(0 到 startPos)+ 要插入的新值(value)+ 从结束位置之后的部分(endPos 到原始文本值的末尾)。

function innerCont(value) {
            const adom = document.activeElement;
            const startPos = adom.selectionStart;
            const endPos = adom.selectionEnd;

            adom.value = adom.value.substring(0, startPos) + value + adom.value.substring(endPos, adom.value.length);

        }

到这里就就已经基本实现了 虚拟键盘的基本功能。

  1. 完善虚拟键盘功能
<!DOCTYPE html>
<html>

<head>
    <title>Virtual keyboard</title>
    <style>
        #virtualKeyboard {
            width: 600px;
        }

        .row {
            display: flex;
        }

        .key {
            width: 40px;
            height: 40px;
            background-color: #ccc;
            display: flex;
            justify-content: center;
            align-items: center;
            margin: 2px;
        }
        .key-auto {
            flex: auto;
        }
        input:focus,textarea:focus {
            border: 1px solid red;
            background-color:yellow;
        }
    </style>
</head>

<body>
    <div id="virtualKeyboard">
        <div class="row">
            <button class="key key-f">`</button>
            <button class="key key-f">1</button>
            <button class="key key-f">2</button>
            <button class="key key-f">3</button>
            <button class="key key-f">4</button>
            <button class="key key-f">5</button>
            <button class="key key-f">6</button>
            <button class="key key-f">7</button>
            <button class="key key-f">8</button>
            <button class="key key-f">9</button>
            <button class="key key-f">0</button>
            <button class="key key-f">-</button>
            <button class="key key-f">=</button>
            <button class="key key-auto">Del</button>
        </div>
        <div class="row">
            <button class="key key-auto">Tab</button>
            <button class="key key-u">q</button>
            <button class="key key-u">w</button>
            <button class="key key-u">e</button>
            <button class="key key-u">r</button>
            <button class="key key-u">t</button>
            <button class="key key-u">y</button>
            <button class="key key-u">u</button>
            <button class="key key-u">i</button>
            <button class="key key-u">o</button>
            <button class="key key-u">p</button>
            <button class="key key-f">[</button>
            <button class="key key-f">]</button>
            <button class="key key-f">\</button>
        </div>
        <div class="row">
            <button class="key key-auto">Caps</button>
            <button class="key key-u">a</button>
            <button class="key key-u">s</button>
            <button class="key key-u">d</button>
            <button class="key key-u">f</button>
            <button class="key key-u">g</button>
            <button class="key key-u">h</button>
            <button class="key key-u">j</button>
            <button class="key key-u">k</button>
            <button class="key key-u">l</button>
            <button class="key key-f">;</button>
            <button class="key key-f">'</button>
            <button class="key key-auto">Enter</button>
        </div>
        <div class="row">
            <button class="key key-auto key-shift">Shift</button>
            <button class="key key-u">z</button>
            <button class="key key-u">x</button>
            <button class="key key-u">c</button>
            <button class="key key-u">v</button>
            <button class="key key-u">b</button>
            <button class="key key-u">h</button>
            <button class="key key-u">n</button>
            <button class="key key-u">m</button>
            <button class="key key-f">,</button>
            <button class="key key-f">.</button>
            <button class="key key-f">/</button>
            <button class="key key-auto">Shift</button>
        </div>
        <div class="row">
            <button class="key key-auto">Space</button>
        </div>
    </div>

    <br />
    <input type="text"  />
    <br /><br />
    <input type="text"  />
    <br /><br />
    <input type="text" />
    <br /><br />
    <input type="text" />
    <br /><br />
    <textarea num="" id="" cols="30" rows="10"></textarea>
    <br /><br />
    <textarea num="" id="" cols="30" rows="10"></textarea>
    <br /><br />

    <script>
        
        const inputTextareaEle = document.querySelectorAll("input, textarea");
        let focusDom = '';
        let activeDom = '';
        let isKeyClick = false;
        let isClickShift = false;
        let isClickCaps = false;
        inputTextareaEle.forEach((ele, eleNum) => {
            ele.addEventListener('blur', e => {
                if (isKeyClick) ele.focus()
            })
        });


        function innerCont(value, type) {
            
            const adom = document.activeElement
            adom.focus()
            const activeValue = adom.value.substr(adom.selectionStart, adom.selectionEnd - adom.selectionStart)
            const startPos = (type == 'del' && activeValue) || type != 'del' ? adom.selectionStart : adom.selectionStart - 1
            const endPos = adom.selectionEnd

            // 保存滚动条
            const restoreTop = adom.scrollTop

            adom.value = adom.value.substring(0, startPos) + value + adom.value.substring(endPos, adom.value.length)
            
            if (restoreTop > 0) adom.scrollTop = restoreTop
            
            adom.focus()
            adom.selectionStart = startPos + value.length
            adom.selectionEnd = startPos + value.length
        }
        function shiftFunc () {
            isClickShift = !isClickShift
            const fuhao = {
                '`': '~',
                '1': '!',
                '2': '@', 
                '3': '#', 
                '4': '$', 
                '5': '%', 
                '6': '^', 
                '7': '&', 
                '8': '*', 
                '9': '(', 
                '0': ')', 
                '-': '_', 
                '=': '+',
                '[': '{', 
                ']': '}',
                '\\': '|',
                ';': ':',
                '\'': '"',
                ',': '<',
                '.': '>',
                '/': '?',
                '~': '`',
                '!': '1',
                '@': '2',
                '#': '3',
                '$': '4',
                '%': '5',
                '^': '6',
                '&': '7',
                '*': '8',
                '(': '9',
                ')': '0',
                '_': '-',
                '+': '=',
                '{': '[',
                '}': ']',
                '|': '\\',
                ':': ';',
                '"': '\'',
                '<': ',',
                '>': '.',
                '?': '/',
            };
            document.querySelectorAll('.key-f').forEach((item) => {
                item.textContent = fuhao[item.textContent]
            })
            if (!isClickCaps) {
                const isUp = document.querySelectorAll('.key-u')[0].textContent == 'Q'
                document.querySelectorAll('.key-u').forEach((item) => {
                    item.textContent = isUp ? item.textContent.toLocaleLowerCase() : item.textContent.toLocaleUpperCase()
                })
            }
        }
        document.addEventListener('mousedown', (e) => {
            if (e.target.className.includes('key')) {
                isKeyClick = true
                let keyVal = e.target.textContent
                if (keyVal == 'Del') return innerCont('', 'del')
                if (keyVal == 'Enter') return innerCont('\n')
                if (keyVal == 'Tab') return innerCont('\t')
                if (keyVal == 'Space') return innerCont(' ')
                if (keyVal == 'Caps') {
                    const isUp = document.querySelectorAll('.key-u')[0].textContent == 'Q'
                    document.querySelectorAll('.key-u').forEach((item) => {
                        item.textContent = isUp ? item.textContent.toLocaleLowerCase() : item.textContent.toLocaleUpperCase()
                        isClickCaps = !isUp
                    })
                    return
                }
                if (keyVal == 'Shift') {
                    shiftFunc()
                    return
                }
                innerCont(keyVal)
                if (isClickShift) shiftFunc()
            } else {
                isKeyClick = false
            }
        })
    </script>
</body>

</html>