虚拟键盘的主要核心点——输入的前提是:必须记录存在焦点的东西,有焦点可以输入,没有就不行。
- 基本的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)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);
}
到这里就就已经基本实现了 虚拟键盘的基本功能。
- 完善虚拟键盘功能
<!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>