最近开发中遇到一个需求:
焊接机器人的屏幕上集成web前端网页, 但是没有接入键盘。这就需要web端开发一个虚拟键盘,在网上找个很多虚拟键盘没有特别适合,索性自己写个简单的
图片:
代码:
(代码可能比较垃圾冗余,也没时间优化,凑合看吧)
第一步:创建键盘组件
为了方便使用,我将键盘写成组件的方式,在app.vue中引入可以全局使用
<template>
<el-dialog
v-model="isShows"
append-to-body="true"
width="80%"
@close="dialogClose"
>
<div
class="keyboard_pop"
@click.self="isShows = false"
>
<div class="input">
<span
v-if="!showText"
class="placeholder"
>
请输入内容</span
>
<p v-else>
{{ showText }}
</p>
</div>
<div class="keyboard">
<div
v-for="(row, index) in keyList"
:key="index"
class="keyRow"
>
<div
v-for="(key, keyIndex) in row"
:key="keyIndex"
:class="{
delete: key === 'Delete',
capslock: key === 'Caps',
space: key === 'Space',
capsed: key === 'Caps' && hasCapsed,
li: true,
}"
@click="clickKey(key)"
>
{{ key }}
</div>
</div>
</div>
</div>
</el-dialog>
</template>
<script setup name="template">
import useHomeStore from "@/stores/home"; //引入仓库
import { storeToRefs } from "pinia"; //引入pinia转换
import { ElMessage } from "element-plus";
const userInfoStore = useHomeStore();
const { isShows, showText, inputType } = storeToRefs(userInfoStore); // 响应式
const emits = defineEmits(["updatekey"]);
const keyvalue = ref(showText); //键盘输入值 this.keyboardtext
const normalKeyList = ref([
["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "="],
["q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "[", "]", "\\"],
["a", "s", "d", "f", "g", "h", "j", "k", "l", ";", "'", "Enter"],
["z", "x", "c", "v", "b", "n", "m", ",", ".", "/"],
["Caps", "Space", "Delete"],
]); //正常键盘列表
const capsedKeyList = ref([
["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "="],
["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\"],
["A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "Enter"],
["Z", "X", "C", "V", "B", "N", "M", ",", ".", "/"],
["Caps", "Space", "Delete"],
]); //大写键盘列表
const keyList = ref(normalKeyList.value); //键盘列表
const hasCapsed = ref(false); //是否大写
const clickKey = (key) => {
if (inputType.value == "number") {
const flag = [
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
'.',
"Enter",
"Delete",
].includes(key);
if (!flag) {
return ElMessage({
message: "请输入数字",
type: "warning",
});
}
}
switch (key) {
case "Enter":
userInfoStore.showText = keyvalue.value;
userInfoStore.clickEnter();
break;
case "Delete":
let kbt = keyvalue.value;
keyvalue.value = kbt.length ? kbt.substring(0, kbt.length - 1) : kbt;
break;
case "Space":
keyvalue.value += " ";
break;
case "Caps":
hasCapsed.value = !hasCapsed.value;
keyList.value = hasCapsed.value ? capsedKeyList.value : normalKeyList.value;
break;
default:
keyvalue.value += key;
break;
}
userInfoStore.showText = keyvalue.value;
const dialogClose = () => {
//遮罩层关闭
userInfoStore.dialogClose();
};
};
</script>
<style lang="scss" scoped>
.input {
min-height: 80px;
border: 1px solid #ccc;
border-radius: 5px;
margin-bottom: 30px;
padding: 10px;
}
.keyboard_pop {
width: 100%;
}
.keyRow {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.keyboard {
margin: 0;
padding: 0;
list-style: none;
user-select: none;
background: #fff;
width: 100%;
padding: 5px 15px;
overflow: auto;
.li {
padding: 8px 18px;
text-align: center;
background: #fff;
border-radius: 15px;
font-size: 18px;
font-weight: 500;
box-shadow: 0 3px 6px 0px #cac9c9;
&:hover {
cursor: pointer;
background: #03ba82;
color: #fff;
}
&:active {
top: 1px;
left: 1px;
}
}
.delete {
width: 100px;
}
.space {
width: 300px;
}
.capsed {
position: relative;
top: 1px;
left: 1px;
border-color: #e5e5e5;
cursor: pointer;
}
}
</style>
第二步:注册自定义事件
(给元素绑定自定义事件,input获取光标直接可以显示虚拟键盘,方便操作!)
const isInput = (dom) => {
// 检查dom是否是input元素
if (dom.tagName === "INPUT") {
return dom;
}
// 如果不是input元素,且有子节点,则递归查找子节点
if (dom.children) {
for (let child of dom.children) {
let input = isInput(child);
if (input) {
return input; // 如果找到input元素,立即返回
}
}
}
// 如果没有找到input元素,返回null
return null;
};
import pinia from "@/stores/index";
import useHomeStore from "@/stores/home"; //引入仓库
const userInfoStore = useHomeStore(pinia);
export const showKeyboard = {
mounted(el, binding) {
const input = isInput(el);
if (!input) {
return console.log("绑定错误,没有input元素");
}
//保存input元素
userInfoStore.inputDom = input;
//给input注册input事件
input.addEventListener("focus", function (e) {
console.log("聚焦了");
console.dir(e);
//保存input输入框的类型
userInfoStore.inputType = e.target.type;
userInfoStore.inputDom = e.target;
userInfoStore.isShows = true;
userInfoStore.showText = e.target.value;
e.target.blur();
});
// input.addEventListener("blur", function (e) {
// console.log("失去聚焦了");
// // userInfoStore.isShows = false;
// });
},
};
第三步:pinia保存全局变量
(全局保存变量,各个input输入的值方便保存)
import { defineStore } from "pinia";
const useHomeStore = defineStore("Home", {
// defineStore('userInfo',{}) Home就是这个仓库的名称name
state: () => ({
inputDom: null,
isShows: false,
showText: "",
inputType: "",
}),
actions: {
//点击键盘确定
clickEnter() {
//this.inputDom.change()
console.log(this.showText);
this.inputDom.value = JSON.parse(JSON.stringify(this.showText))
console.dir(this.inputDom);
//手动触发change事件
// 什么是dispatchEvent
// 向一个指定的事件目标派发一个事件,
// 并以合适的顺序同步调用目标元素相关的事件处理函数。
// 标准事件处理规则(包括事件捕获和可选的冒泡过程)
// 同样适用于通过手动的使用dispatchEvent()方法派发的事件。
this.inputDom.dispatchEvent(new Event("input"));
this.inputDom.dispatchEvent(new Event("change"));
this.showText = "";
this.inputDom.blur();
this.isShows = false;
this.inputDom = null;
this.inputType = "";
},
//遮罩层关闭
dialogClose() {
this.showText = "";
this.isShows = false;
this.inputDom.blur();
this.inputDom = null;
this.inputType = "";
},
},
});
export default useHomeStore;