效果图

官网

simple-keyboard官网:https://hodgef.com/simple-keyboard/ 打不开的话请用魔法

不足

中文语言包支持度不够。不过自己可以找语言包替换

依赖安装

npm install simple-keyboard --save
npm install simple-keyboard-layouts --save // 中文语言包

组件代码

<template>
<el-input ref="inputRef" v-model="model" @focus="focusInput" @keyup.enter="handleEnter" v-bind="$attrs">
<template v-for="(item, index) in $slots" :key="index" #[index]>
<slot :name="index"></slot>
</template>
</el-input> <el-popover
:visible="visible"
:virtual-ref="inputRef"
virtual-triggering
placement="bottom"
:width="width"
:show-arrow="false"
:hide-after="0"
popper-style="padding: 0px;color:#000"
:persistent="false"
popper-class="keyboard-popper"
@after-leave="afterLeave"
@after-enter="afterEnter"
>
<div v-if="visible" class="simple-keyboard"></div>
</el-popover>
</template> <script setup lang="ts">
import Keyboard from 'simple-keyboard'
import 'simple-keyboard/build/css/index.css'
import layout from 'simple-keyboard-layouts/build/layouts/chinese.js'
defineOptions({
inheritAttrs: false
})
const model = defineModel<string>()
const emits = defineEmits(['onChange', 'enter', 'close', 'focus'])
const props = defineProps({
layoutName: {
type: String,
default: 'default'
},
// 保留几位小数 layoutName为number时生效
precision: {
type: Number,
default: 2
},
// 获取焦点打开键盘
isOpen: {
type: Boolean,
default: true
}
})
const keyboard = ref<any>(null)
const visible = ref(false)
const inputRef = ref()
const width = ref(1000)
if (props.layoutName == 'number') width.value = 300
const displayDefault = ref({
'{bksp}': 'backspace',
'{lock}': 'caps',
'{enter}': 'enter',
'{tab}': 'tab',
'{shift}': 'shift',
'{change}': 'en',
'{space}': 'space',
'{clear}': '清空',
'{close}': '关闭',
'{arrowleft}': '←',
'{arrowright}': '→'
}) const open = () => {
if (visible.value) return
inputRef.value.focus()
emits('focus')
visible.value = true
}
const focusInput = () => {
if (visible.value) return
emits('focus')
if (props.isOpen) visible.value = true
}
const afterEnter = () => {
// 存在上一个实例时移除元素
const prevKeyboard = document.querySelectorAll('.init-keyboard')
if (prevKeyboard.length > 0) prevKeyboard[0]?.remove()
keyboard.value = new Keyboard('simple-keyboard', {
onChange: onChange,
onKeyPress: onKeyPress,
onInit: onInit,
layout: {
// 默认布局
default: [
'` 1 2 3 4 5 6 7 8 9 0 - = {bksp}',
'{tab} q w e r t y u i o p [ ] \\',
"{lock} a s d f g h j k l ; ' {enter}",
'{change} z x c v b n m , . / {clear}',
'{arrowleft} {arrowright} {space} {close}'
],
// 大小写
shift: [
'~ ! @ # $ % ^ & * ( ) _ + {bksp}',
'{tab} Q W E R T Y U I O P { } |',
'{lock} A S D F G H J K L : " {enter}',
'{change} Z X C V B N M < > ? {clear}',
'{arrowleft} {arrowright} {space} {close}'
],
// 数字布局
number: ['7 8 9', '4 5 6', '1 2 3', '. 0 {bksp}', '{arrowleft} {arrowright} {clear} {close}']
},
layoutName: props.layoutName,
display: displayDefault.value,
theme: 'hg-theme-default init-keyboard' // 添加自定义class处理清空逻辑
})
}
const afterLeave = () => {
displayDefault.value['{change}'] = 'en'
document.removeEventListener('click', handlePopClose)
}
const onInit = (keyboard: any) => {
keyboard.setInput(model.value)
keyboard.setCaretPosition(inputRef.value?.ref.selectionEnd)
document.addEventListener('click', handlePopClose)
}
const onChange = (input: any) => {
model.value = input
emits('onChange', input)
}
const onKeyPress = (button: any) => {
if (button !== '{close}') handleFocus()
if (button === '{lock}') return handleLock()
if (button === '{change}') return handleChange()
if (button === '{clear}') return handleClear()
if (button === '{enter}') return handleEnter()
if (button === '{close}') return handleClose()
if (button === '{arrowleft}') return handleArrow(0)
if (button === '{arrowright}') return handleArrow(1)
}
const handleLock = () => {
let currentLayout = keyboard.value.options.layoutName
let shiftToggle = currentLayout === 'default' ? 'shift' : 'default' keyboard.value.setOptions({
layoutName: shiftToggle
})
}
const handleChange = () => {
let layoutCandidates = keyboard.value.options.layoutCandidates
// 切换中英文输入法
if (layoutCandidates != null && layoutCandidates != undefined) {
displayDefault.value['{change}'] = 'en'
keyboard.value.setOptions({
layoutName: 'default',
layoutCandidates: null,
display: displayDefault.value
})
} else {
displayDefault.value['{change}'] = 'cn'
keyboard.value.setOptions({
layoutName: 'default',
layoutCandidates: (layout as any).layoutCandidates,
display: displayDefault.value
})
}
}
const handleClear = () => {
keyboard.value.clearInput()
model.value = ''
}
const handleEnter = () => {
emits('enter')
}
const handleClose = () => {
visible.value = false
if (props.layoutName == 'number') {
// 处理精度
model.value = model.value?.replace(new RegExp(`(\\d+)\\.(\\d{${props.precision}}).*$`), '$1.$2').replace(/\.$/, '')
}
emits('close')
}
const handleArrow = (num: number) => {
// 处理左右箭头下标位置
const index = keyboard.value.getCaretPositionEnd()
if (num == 0 && index - 1 >= 0) {
keyboard.value.setCaretPosition(index - 1)
} else if (num == 1 && index + 1 <= (model.value?.length || 0)) {
keyboard.value.setCaretPosition(index + 1)
}
}
const handleFocus = () => {
// 处理焦点显示
setTimeout(() => {
const index = keyboard.value.getCaretPositionEnd()
inputRef.value.ref.selectionStart = inputRef.value.ref.selectionEnd = index
inputRef.value.focus()
}, 0)
}
const handlePopClose = (e: any) => {
// 虚拟键盘区域 输入框区域 中文选项区域
if (
(e.target as Element).closest('.keyboard-popper') ||
e.target == inputRef.value?.ref ||
/hg-candidate-box/.test(e.target.className)
) {
return
}
handleClose()
}
const close = () => {
handleClose()
}
defineExpose({ inputRef, visible, open, close })
</script> <style>
.hg-theme-default .hg-button.hg-button-arrowleft,
.hg-theme-default .hg-button.hg-button-arrowright {
max-width: 70px;
}
.hg-theme-default .hg-button.hg-button-close {
max-width: 100px;
}
.hg-layout-number .hg-button.hg-button-close {
max-width: none;
}
.hg-layout-number .hg-button.hg-button-bksp {
max-width: 92px;
}
</style>

vue3中使用simple-keyboard实现虚拟键盘(带中文切换数字键盘)的更多相关文章

  1. (译)iPhone: 用公开API创建带小数点的数字键盘 (OS 3.0, OS 4.0)

    (译)iPhone: 用公开API创建带小数点的数字键盘 (OS 3.0, OS 4.0) 更新:ios4.1现在已经将这个做到SDK了.你可以设置键盘类型为UIKeyboardTypeDecimal ...

  2. 一个数字键盘引发的血案——移动端H5输入框、光标、数字键盘全假套件实现

    https://juejin.im/post/5a44c5eef265da432d2868f6 为啥要写假键盘? 还是输入框.光标全假的假键盘? 手机自带的不用非得写个假的,吃饱没事干吧? 装逼?炫技 ...

  3. VirtualBox中出现UUID have already exists ,并且数字键盘numlock效果相反

    原文地址:https://www.cnblogs.com/xqzt/p/5053338.html 原因:由于linux密码登录错误,修改也报错误,所以只能重新安装虚拟机并在其中安装镜像文件,但是安装镜 ...

  4. 在Win7中IIS配置Asp.Net虚拟文件夹的方法及错误总结!

    在Win7中IIS配置Asp.Net虚拟文件夹的方法总结! 一.右键[站点].点击[加入虚拟文件夹]或[虚拟应用程序],笔者建议最好建立虚拟应用程序,由于这就跟一个站点差点儿相同.不用考虑路径问题. ...

  5. rancher中级(二)(rancher中添加证书及操作虚拟主机)

    制作一个ssl证书 首先了解关于ssl证书的背景知识:http://www.cnblogs.com/zxj015/p/4458066.html SSL证书包括: 1,CA证书,也叫根证书或者中间级证书 ...

  6. jQuery 虚拟数字键盘代码

    先上效果:    js直接应用:  $('input').mynumkb(); 就出来效果 HTML: <input maxlength="4" type="tex ...

  7. vue3中使用axios如何去请求数据

    在vue2中一般放在created中,但是在vue3中取消了created生命周期,请求方式有两种 直接在setup中去获取数据 setup(props) { const data = reactiv ...

  8. vue3中watch函数

    watch 监听普通类型 let count = ref(1); const changeCount = () => { count.value+=1 }; watch(count, (newV ...

  9. 端午总结Vue3中computed和watch的使用

    1使用计算属性 computed 实现按钮是否禁用 我们在有些业务场景的时候,需要将按钮禁用. 这个时候,我们需要使用(disabled)属性来实现. disabled的值是true表示禁用.fals ...

  10. vue 3 学习笔记 (七)——vue3 中 computed 新用法

    vue3 中 的 computed 的使用,由于 vue3 兼容 vue2 的选项式API,所以可以直接使用 vue2的写法,这篇文章主要介绍 vue3 中 computed 的新用法,对比 vue2 ...

随机推荐

  1. JS leetcode 拥有最多糖果的孩子 题解分析,六一快乐。

    壹 ❀ 引 今天是六一儿童节,leetcode的每日一题也特别可爱,那么今天我们来解决一道与糖果有关的问题,题目来源1431. 拥有最多糖果的孩子,题目描述如下: 给你一个数组 candies 和一个 ...

  2. NC51178 没有上司的舞会

    题目链接 题目 题目描述 Ural大学有N名职员,编号为1~N. 他们的关系就像一棵以校长为根的树,父节点就是子节点的直接上司. 每个职员有一个快乐指数,用整数 \(Hi\) 给出,其中 \(1\le ...

  3. OCR 01: EasyOCR

    Catalog OCR 01: EasyOCR OCR 02: Tesseract-OCR OCR 03: PaddleOCR Related Links Official site with onl ...

  4. pta-神坛

    [神坛]pta *相邻两条边围成的三角形面积会是最小的 极角排序+叉积计算三角形面积 #include<bits/stdc++.h> #define int long long using ...

  5. 如何申请免费的SSL证书和通配符证书

    一,目前免费证书普遍存在的痛点 证书有效期普遍只有3个月 2023年12月22日阿里云官方发布公告,后续免费证书的有效期统一调整为3个月,我相信其它厂商很快也会做出调整. 调整为3个月有效期后,意味着 ...

  6. Java JVM——3.运行时数据区概述及线程

    运行时数据区概述 在JVM 中的位置 内部划分 当我们通过前面的:类的加载 → 验证 → 准备 → 解析 → 初始化 这几个阶段完成后,执行引擎就会对我们的类进行使用,同时执行引擎将会使用到我们的运行 ...

  7. 如何在 WindowManager.addView 中使用 Jetpack Compose

    如何在 WindowManager.addView 中使用 Jetpack Compose 一.引出问题 Android 开发中,很常见的一个场景,通过 WindowManager.addView() ...

  8. vue 项目npm run dev(启动)时报错The service was stopped

    vue项目yarn upgrade后vite build报错,如何项目也运行不起来了. 报错截图: 解决办法: 删除node_modules文件夹,然后执行yarn install重新生成心的node ...

  9. 【生成对抗网络学习 其二】GAN(keras实现)代码阅读笔记

    想来想去还是记录一下吧,主要是怕以后时间长忘了 好记性不如烂笔头 代码来自eriklindernoren的开源GAN实现:https://github.com/eriklindernoren/Kera ...

  10. 骚操作之 持有 ReadOnlySpan 数据

    ReadOnlySpan<T> 可以说现在高性能操作的重要基石 其原理有兴趣的同学可以看 2018 的介绍Span<T>文章 其为了保障大家安全使用做了相应的限制 那么有没方法 ...