1、效果图
2、使用方式
<Keyboard v-if="show" @close="show = false" :inputDom="$refs.input" />
封装的数字键盘 Keyboard.vue 组件代码
<template><divclass="keyboard"ref="keyboard":style="{ left: moveX + 'px', bottom: moveY + 'px' }"><div class="drag" @mousedown="keyDown"><p></p><div @click="$emit('close')" @mousedown.stop @mousemove.stop><img src="./arrow.svg" alt="" /></div></div><div class="main"><div class="left"><divv-for="text in symbols":key="text"@click="insertTxtAndSetcursor(text)">{{ text }}</div></div><div class="right"><div class="left"><divclass="item"v-for="i in 9":key="i"@click="insertTxtAndSetcursor(i)">{{ i }}</div></div><div class="right"><div class="item" @click="insertTxtAndSetcursor('', true)"><img src="./delete.svg" alt="" /></div><div class="item" @click="insertTxtAndSetcursor(' ')"><img src="./blank.svg" alt="" /></div><div class="item" @click="insertTxtAndSetcursor(0)">0</div></div></div></div></div>
</template><script scoped>
export default {data() {return {symbols: ["+", "-", "=", ".", "/", "@"],flag: false,seto: null,downInfo: {},moveX: 0,moveY: 0,};},props: {inputDom: {type: Node,default: null,},},mounted() {document.addEventListener("mousemove", this.keyMove);},methods: {// 输入文本insertTxtAndSetcursor(text, del) {let element = this.inputDom; // 获取到指定标签let startPos = element.selectionStart; // 获取光标开始的位置let endPos = element.selectionEnd; // 获取光标结束的位置if (startPos === undefined || endPos === undefined) return; // 如果没有光标位置 不操作let oldTxt = element.value; // 获取输入框的文本内容let result = "";// 光标位置不能小于0const num = startPos - 1;if (del && num >= 0) {result = oldTxt.substring(0, startPos - 1) + oldTxt.substring(endPos); // 将文本插入} else {result =oldTxt.substring(0, startPos) + text + oldTxt.substring(endPos); // 将文本插入}element.value = result; // 将拼接好的文本设置为输入框的值element.focus(); // 重新聚焦输入框if (del && num >= 0) {element.selectionStart = startPos - 1 + (text + "").length; // 设置光标开始的位置element.selectionEnd = startPos - 1 + (text + "").length; // 设置光标结束的位置} else {element.selectionStart = startPos + (text + "").length; // 设置光标开始的位置element.selectionEnd = startPos + (text + "").length; // 设置光标结束的位置}},keyUp() {this.flag = false;document.removeEventListener("mouseup", this.keyUp);document.removeEventListener("mouseleave", this.keyUp);},keyDown(e) {this.downInfo.x = e.pageX;this.downInfo.y = e.pageY;this.downInfo.left = this.moveX;this.downInfo.bottom = this.moveY;this.seto = setTimeout(() => {this.flag = true;document.addEventListener("mouseup", this.keyUp);document.addEventListener("mouseleave", this.keyUp);clearTimeout(this.seto);}, 1000);},keyMove(e) {if (this.flag) {const maxh =(document.clientHeight ||document.documentElement.clientHeight ||document.body.clientHeight) - this.$refs.keyboard.clientHeight;const htj = this.downInfo.bottom + this.downInfo.y - e.pageY;const maxw =(document.clientWidth ||document.documentElement.clientWidth ||document.body.clientWidth) - this.$refs.keyboard.clientWidth;const wtj = this.downInfo.left - (this.downInfo.x - e.pageX);if (wtj <= maxw && wtj >= 0) {//确保键盘始终在屏幕可见范围内this.moveX = wtj;}if (htj <= maxh && htj >= 0) {//确保键盘始终在屏幕可见范围内this.moveY = htj;}}},},
};
</script><style lang="scss" scoped>
.keyboard {width: 100vw;height: 245px;max-width: 353px;min-width: 285px;position: fixed;bottom: 0;left: 0;background-color: #d6d7db;> .drag {width: 100%;height: 15%;display: flex;align-items: center;justify-content: center;position: relative;> p {width: 30%;height: 13%;border-radius: 5px;background-color: #fff;}> div {width: 18.3%;height: 100%;position: absolute;top: 50%;right: 0;transform: translateY(-50%);&::before {width: 1px;content: "";height: 60%;background-color: #fff;position: absolute;top: 50%;left: 0;transform: translateY(-50%);}> img {user-select: none;width: 45%;position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);}}}> .main {height: calc(100% - 15%);display: flex;justify-content: space-between;padding: 2%;> .left {flex: 15;margin-right: 2%;height: 100%;border-radius: 6px;background-color: #fff;overflow: auto;user-select: none;&::-webkit-scrollbar {display: none;}> div {font-size: 20px;height: 25%;display: flex;align-items: center;justify-content: center;&:active {background-color: #a1a8b8;}}}> .right {height: 100%;border-radius: 5px;flex: 77;display: flex;justify-content: space-between;user-select: none;> .left {height: 100%;display: flex;flex-wrap: wrap;justify-content: space-between;align-content: space-between;width: 77%;> .item {background-color: #fff;height: 30.8%;width: 31.5%;display: flex;align-items: center;justify-content: center;border-radius: 5px;font-size: 18px;&:active {background-color: #adb4be;}&:nth-of-type(3n) {margin-right: 0;}&:nth-of-type(7),&:nth-of-type(8),&:nth-of-type(9) {margin-bottom: 0;}}}> .right {width: 21%;height: 100%;display: flex;flex-direction: column;justify-content: space-between;> .item {border-radius: 5px;display: flex;align-items: center;justify-content: center;height: 30.8%;background-color: #adb4be;> img {width: 40%;}&:active {background-color: #7e8492;}}}}}
}
</style>
3、使用方式代码
<template><div id="app"><input ref="input" type="text" @focus="show = true" v-model="text" /><Keyboard v-if="show" @close="show = false" :inputDom="$refs.input" /></div>
</template><script scoped>
import Keyboard from "./Keyboard.vue";
export default {components: { Keyboard },data() {return { show: false, text: "" };},
};
</script><style lang="scss" scoped>
#app {width: 100vw;height: 100vh;background-color: #000;> input {height: 25px;display: block;margin: 0 auto;}
}
</style>