个人在做一个只有触屏的React前端开发,需要输入文本,找了一圈没有好用的React虚拟键盘插件。故自己写了一个,分享给大家。

代码如下:

文件名: VK.jsx

/*--
海皮智造 虚拟键盘 20200930
=============================================React 内调用说明:
import { VirtualKeyboard } from './VK'
VirtualKeyboard 有2个参数,3个方法。
//
参数1:
VirtualKeyboard.isDisableEnter=true|false
是否禁用Enter键,默认为true。参数2:
VirtualKeyboard.isDisableTab=true|false
是否禁用Tab键,默认为true。
------------------------
方法1:
.showKeyboardSetState(valueObject,reactComponent)
显示虚拟键盘,此方式主要用于Antd Input组件,由于Antd的输入组件直接修改dom的value不生效,故只能传入值Object对象。
valueObject 是一个Object,Object对象必须使用value属性来传递值。
reactComponent 是当前React Component,用于按键后setState更新显示。
如下例子:
let V={value:'123'}
<Input onClick={()=>VirtualKeyboard.showKeyboardSetState(V,this)} value={V.value}/>方法2:
.showKeyboard(e)
显示虚拟键盘,此方式主要用于大部分模式。
参数e可是3种类型,
1、字符串,即要联动的dom的id
使用举例: VirtualKeyboard.showKeyboard("inputA")
2、直接是要联动的dom对象,
使用举例: VirtualKeyboard.showKeyboard(document.getElementById("xxx"))
3、鼠标/触摸事件
使用举例: <input onClick={VirtualKeyboard.showKeyboard} />方法3:
.closeKeyboard()
用命令来关闭键盘,一般来说用不到。
--*/
import React from 'react';
import ReactDOM from 'react-dom';
class VK extends React.Component {C = ["~`", "!1", "@2", "#3", "$4", "%5", "^6", "&7", "*8", "(9", ")0", "_-", "+=", "Backspace","Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "{[", "}]", "|\\","CapsLock", "A", "S", "D", "F", "G", "H", "J", "L", "L", ":;", "\"'", "Enter","Shift", "Z", "X", "C", "V", "B", "N", "M", "<,", ">.", "?/", "Space"]W = [, , , , , , , , , , , , , 120, 90, , , , , , , , , , , , , 90, 110, , , , , , , , , , , , 135, 140, , , , , , , , , , , 170]F_MouseDown = (e) => {e = e.nativeEventif (e.button !== 0) returnif (e.target.id.indexOf("VK_") !== 0) {if ((e.target.innerText === "Enter" && this.props.values.isDisableEnter === true) || (e.target.innerText === "Tab" && this.props.values.isDisableTab === true)) {return}e.target.style.backgroundColor = "#F80"e.target.style.boxShadow = "0px 0px 4px #000 inset"this.V.keydom = e.targetdocument.addEventListener("mouseup", this.F_KeyMouseUp);return}document.addEventListener("mousemove", this.F_MouseMove);document.addEventListener("mouseup", this.F_MouseUp);this.V.posX = -e.pageXthis.V.posY = -e.pageY}F_MouseMove = (e) => {let tx = this.V.posX + e.pageX + this.V.x;let ty = this.V.posY + e.pageY + this.V.y;this.dom.style.left = tx + 'px'this.dom.style.top = ty + 'px'}F_MouseUp = (e) => {this.V.x = this.V.posX + e.pageX + this.V.x;this.V.y = this.V.posY + e.pageY + this.V.y;document.removeEventListener("mousemove", this.F_MouseMove);document.removeEventListener("mouseup", this.F_MouseUp);}F_KeyMouseUp = (e, dom) => {this.V.keydom.style.backgroundColor = "#FFF"this.V.keydom.style.boxShadow = nulldocument.removeEventListener("mouseup", this.F_KeyMouseUp);}F_TouchStart = (e) => {e = e.nativeEventif (e.target.id.indexOf("VK_") !== 0) {if ((e.target.innerText === "Enter" && this.props.values.isDisableEnter === true) || (e.target.innerText === "Tab" && this.props.values.isDisableTab === true)) {return}e.target.style.backgroundColor = "#F80"e.target.style.boxShadow = "0px 0px 4px #000 inset"this.V.keydom = e.targetdocument.addEventListener("touchend", this.F_KeyTouchEnd);return}document.addEventListener("touchmove", this.F_TouchMove);document.addEventListener("touchend", this.F_TouchEnd);this.V.posX = -e.targetTouches[0].pageXthis.V.posY = -e.targetTouches[0].pageY}F_TouchMove = (e) => {let tx = this.V.posX + e.targetTouches[0].pageX + this.V.x;let ty = this.V.posY + e.targetTouches[0].pageY + this.V.y;this.dom.style.left = tx + 'px'this.dom.style.top = ty + 'px'}F_TouchEnd = (e) => {this.V.x = this.V.posX + e.changedTouches[0].pageX + this.V.x;this.V.y = this.V.posY + e.changedTouches[0].pageY + this.V.y;document.removeEventListener("touchmove", this.F_TouchMove);document.removeEventListener("touchend", this.F_TouchEnd);}F_KeyTouchEnd = (e) => {this.V.keydom.style.backgroundColor = "#FFF"this.V.keydom.style.boxShadow = nulldocument.removeEventListener("touchend", this.F_KeyTouchEnd);}F_KeyDown = (e) => {let dom = e.targetlet txt = dom.innerTextif (txt === "CapsLock") {this.V.isCaps = !this.V.isCapsif (this.V.isCaps) {dom.style.backgroundColor = "#F80"} else {dom.style.backgroundColor = "#FFF"}this.setState({})} else if (txt === "Shift") {this.V.isShift = !this.V.isShiftif (this.V.isShift) {dom.style.backgroundColor = "#F80"} else {dom.style.backgroundColor = "#FFF"}this.setState({})} else if (txt === "Enter") {if (this.props.values.isDisableEnter === false) {this.F_ChangeInput(String.fromCharCode(13))}} else if (txt === "Space") {this.F_ChangeInput(" ")} else if (txt === "Tab") {if (this.props.values.isDisableTab === false) {this.F_ChangeInput(String.fromCharCode(9))}} else if (txt === "Backspace") {this.F_ChangeInput(-1)} else if (txt.indexOf("\n") >= 0) {if (this.V.isShift) {this.F_ChangeInput(txt[0])} else {this.F_ChangeInput(txt[2])}} else {if (this.V.isShift) {this.F_ChangeInput(txt.toUpperCase() === txt ? txt.toLowerCase() : txt.toUpperCase())} else this.F_ChangeInput(txt)}}render() {let keyStyle = {boxSizing: "border-box",float: "left",height: 60,margin: 2.5,borderRadius: 4,border: "1px solid #333",textAlign: "center",cursor: "pointer",}return (<div onContextMenu={e => e.preventDefault()} tabIndex="-1" id="VK_Main" ref={dom => this.dom = dom} style={{ outline: 'none', top: this.V.y, left: this.V.x, position: 'absolute', zIndex: '999999999', backgroundColor: '#AAA', padding: 3, width: 970, fontSize: 20, border: '1px solid #444', borderRadius: 8, userSelect: 'none' }} onMouseDown={this.F_MouseDown} onTouchStart={this.F_TouchStart} onBlur={this.F_Close}><div id="VK_Title" style={{ fontSize: 14, margin: 5, textAlign: "right" }}><span id="VK_Tip" style={{ float: 'left' }}>海皮智造 © 虚拟键盘</span>如虚拟键盘遮挡显示内容,可以拖动移开或 <button style={{ borderRadius: 6, border: '1px dotted #333' }} onClick={this.F_Close}>关闭虚拟键盘</button></div><div id="VK_Keys" style={{ height: 67, lineHeight: 67 }} onClick={this.F_KeyDown} >{this.C.map((c, n) => {if (c.length === 2) {return (<div key={n} style={{ ...keyStyle, width: this.W[n] ? this.W[n] : 60, lineHeight: '28px', backgroundColor: "#fff" }}>{c[0]}<br />{c[1]}</div>)} else {return <div key={n} style={{ ...keyStyle, width: this.W[n] ? this.W[n] : 60, lineHeight: '60px', backgroundColor: (c === "Tab" && this.props.values.isDisableTab) || (c === "Enter" && this.props.values.isDisableEnter) ? "#888" : "#fff" }}>{c.length === 1 ? (this.V.isCaps ? c.toUpperCase() : c.toLocaleLowerCase()) : c}</div>}})}</div></div>)}constructor(props) {super()if (props.values.dom !== null) {this.V.currentDom = props.values.dom}if (props.values.value !== null && props.values.state !== null) {this.V.reactValueObject = props.values.valuethis.V.reactStateObject = props.values.state}let w = document.body.clientWidthlet h = document.body.clientHeightthis.V.x = w / 2 - 970 / 2this.V.y = h - 300}UNSAFE_componentWillUpdate(props) {if (props.values.dom !== null) {this.V.currentDom = props.values.domthis.V.reactValueObject = nullthis.V.reactStateObject = null} else if (props.values.value !== null && props.values.state !== null) {this.V.reactValueObject = props.values.valuethis.V.reactStateObject = props.values.statethis.V.currentDom = null}}componentDidMount() {this.dom.focus()}F_ChangeInput = (c) => {let inputContent = ""if (this.V.currentDom !== null) {inputContent = this.V.currentDom.innerText || this.V.currentDom.textContent || this.V.currentDom.value} else inputContent = this.V.reactValueObject.value;inputContent = inputContent.toString()let strArr = inputContent.split('')if (c === -1) {strArr.pop()} else strArr.push(c)if (this.V.currentDom !== null) {if (this.V.currentDom.nodeName === "INPUT") {this.V.currentDom.value = strArr.join('')} else if (this.V.currentDom.nodeName !== undefined) {this.V.currentDom.innerHTML = strArr.join('')}} else if (this.V.reactStateObject !== null && this.V.reactValueObject !== null) {this.V.reactValueObject.value = strArr.join('')this.V.reactStateObject.setState({})}}V = {isCaps: false,isShift: false,currentDom: null,reactValueObject: null,reactStateObject: null}F_Close = () => {this.props.values.closeKeyboard()}
}
const data = {VK: VK.prototype,div: null,props: {}
}
export const VirtualKeyboard = {isDisableEnter: true,isDisableTab: true,showKeyboardSetState: (valueObject, reactComponent) => {data.props.value = valueObjectdata.props.state = reactComponentdata.props.dom = nullif (data.div !== null) {data.VK.setState({})} else {data.props.closeKeyboard = VirtualKeyboard.closeKeyboarddata.props.isDisableEnter = VirtualKeyboard.isDisableEnterdata.props.isDisableTab = VirtualKeyboard.isDisableTablet body = document.getElementsByTagName("body")[0]if (body === undefined) returnlet div = document.createElement("div")data.div = divbody.appendChild(div)let V = <VK ref={dom => data.VK = dom} values={data.props} />ReactDOM.render(V, div)}},showKeyboard: (e) => {data.props.value = nulldata.props.state = nulldata.props.dom = nullif (typeof (e) === "string") {let dom = document.getElementById(e)if (dom !== null) {data.props.dom = dom}} else if (typeof (e) === "object") {if (typeof (e.type) === "string" && typeof (e.nodeName) === "string") {data.props.dom = e} else if (e.target !== undefined) {e = e.targetif (typeof (e.type) === "string" && typeof (e.nodeName) === "string") {data.props.dom = e}}}if (data.props.dom === null) returnif (data.div !== null) {data.VK.setState({})} else {data.props.closeKeyboard = VirtualKeyboard.closeKeyboarddata.props.isDisableEnter = VirtualKeyboard.isDisableEnterdata.props.isDisableTab = VirtualKeyboard.isDisableTablet body = document.getElementsByTagName("body")[0]if (body === undefined) returnlet div = document.createElement("div")data.div = divbody.appendChild(div)let V = <VK ref={dom => data.VK = dom} values={data.props} />ReactDOM.render(V, div)}},closeKeyboard: () => {ReactDOM.render(null, data.div)data.div.remove()data.div = null}
}

调用例子:例子中的<Input /> 是AntD的组件。

import { VirtualKeyboard } from './VK';class Test extends React.Component {V={value:"hello"}render() {return <Input onClick={() => VirtualKeyboard.showKeyboardSetState(this.V, this)} value={this.V.value} />}
}

好用拿走,记得点赞一个。

自己做了一款实用 React 虚拟键盘组件,支持AntD,可用于触屏输入文本内容。相关推荐

  1. vue 管理后台 使用虚拟键盘组件 支持中英文切换

    前言:在大型触屏设备(如双屏设备)中,就没有键盘去操作,而且在触屏input或者textarea的输入时候就无法去输入值,没办法触发输入框enter事件,所以就需要去建立一个虚拟键盘去操作 就想着找一 ...

  2. QT 5.7虚拟键盘(支持中文输入)Windows+Ubuntu

    一 Windows下 Qt5.7.1安装虚拟键盘(支持中文输入) 1.环境: windows + qt5.7.1(qt-opensource-windows-x86-mingw530-5.7.1.ex ...

  3. jquery虚拟键盘,支持中文英文数字输入VirtualKeyboard

    https://gitee.com/zhyihui/VirtualKeyboard jQuery虚拟键盘插件,支持 中英文切换.大小写切换等,适合触摸屏应用使用,修改很方便.

  4. 一个VueJS虚拟键盘组件

    这个虚拟键盘就是这样的:详细属性在这里 https://javascript.ctolib.com/vue-touch-keyboard.html 我今天要说的就是不用vue-cli脚手架怎么来使用这 ...

  5. react页面引导组件, 支持语音播报

    页面引导在用户第一次访问网站能过提供很好的提示, 下面介绍基于react写的一个页面引导的组件. 演示地址 效果图 Guide组件的实现 可以把<Guide/>设计成一个容器组件, 因为我 ...

  6. Qt虚拟键盘相关内容

    收集一些关于Qt虚拟键盘的内容,仅供参考.   商业版什么时候就有? Qt虚拟键盘(1.0版本)最早出现在Qt Enterprise Embedded 5.3.0中(2014-05-22)   开源版 ...

  7. 自定义Unity在iOS平台上的虚拟键盘

    日本版本的玩家反馈,iOS的虚拟键盘无法点击确认按钮.观察了游戏内容如下: 发现确认按钮被长条的文本框给挤压了,不能完全显示. 于是观察了隔壁几家游戏是怎么处理虚拟键盘的,如图: 楚留香的键盘:明显重 ...

  8. WIN7自带的虚拟键盘

    虽然我用的输入法不是那么大众,但因为有联网词库那些附加的功能,所以也会担心输入个人信息的安全,一直想找一款小巧的虚拟键盘软件. 今天上网查mklink相关资料时,才知道WIN7系统自带了虚拟键盘,试用 ...

  9. 手部追踪、虚拟键盘、脑机接口……facebook的人机交互技术 | Mixlab 技术前沿

    #智能腕表#.#AR#.#Facebook# Facebook 与智能手表 Facebook 脑机技术 根据 The Information 报道,Facebook 瞄准了智能手表市场.手表的主要功能 ...

最新文章

  1. ​​清华大学举办疫情防控期间首场在线学位论文答辩
  2. LigerUI 使用教程表格篇
  3. LSM树——放弃读能力换取写能力,将多次修改放在内存中形成有序树再统一写入磁盘...
  4. 个人日报0701-0703
  5. 一个简单的Ajax例子
  6. 启动ipython内核发生错误_ipython3启动
  7. linux 7 没有权限访问,[CentOS 7系列]文件或目录的权限与属性
  8. 《利用Python》进行数据分析:Numpy基础1 数组对象ndarray
  9. 各种排序方法的时间复杂度、空间复杂度和稳定性统计表
  10. 什么是软件实施?软件实施前景几何?软件实施的面试题有那些?
  11. BTA前瞻 | 这家区块链公司币圈链圈通吃!专访井通科技CTO杨建新
  12. Java中的UTF-8、UTF-16编码字符所占字节数
  13. J2EE高级开发框架小课程之Spring框架1——Spring创建三种方式:使用无参构造器创建对象(bean标签的方式),使用静态方法创建对象,使用实例方法创建对象(非静态方法)
  14. python tutorial json_Python Tutorial - Parse JSON Objects with Python
  15. 京东jos 获取授权及php-sdk的使用示例
  16. Linux进程间关系之守护进程
  17. Agent系列(一) 什么是Agent
  18. 如何在 Chromebook 上启用开发者模式
  19. 【量化】实战获取Fama-French三因子模型的数据源
  20. 85后蒋凡:28岁实现财务自由、34岁成为阿里万亿电商帝国双掌门,他的人生底层逻辑是什么?...

热门文章

  1. Eclipse中配置maven环境
  2. 耳机不分主从是什么意思_耳机界的颜值担当-Omthing小方盒
  3. 碧蓝航线服务器维护到几点,碧蓝航线3月7日更新了什么 停服维护内容一览
  4. SQL入门知识之计算函数笔记
  5. 【已解决】MongoDB 中根据指定字段筛选出具有重复值的记录
  6. java图形界面详解_JAVA 图形界面开发基础详解
  7. mysql如何批量导入excel_MySQL批量导入Excel数据
  8. 天池工业蒸汽量预测-模型调参
  9. 变-颓势下的凤凰涅槃-发表于程序杂志第12期
  10. js时间函数getTime() 在苹果手机上返回NaN的问题