先上dj(效果)! 先上dj(效果)!
技术:react --ref --父子组件通信 光标事件 字符串方法
兼容:基于Mozilla的浏览器不支持setSelectionRange
注意事项:浏览器默认行为 冒泡 (整个键盘区域有一个click显示键盘,单个数字键另外事件,点击某个位置时(隐藏键盘) 阻止一下冒泡 避免出现冒泡至最外层,导致无法关闭)
光标事件:
//Selection对象表示用户选择的文本范围或插入符号的当前位置。 要获取用于检查或修改的Selection对象,请使用window.getSelection() // selectionSatrt记录鼠标点击的开始位置,selectionEnd记录结束位置
主要思路:点击输入框弹出虚拟键盘,点击键盘某个数字,拿到该值的描述,对input框进行赋值;复杂场景,当点击了1245,想在2和4之间插一个3,这个时候,鼠标按下时 记录下光标的位置(这里需要注意的是浏览器默认行为是fouce,本人这里使用的是click事件,为了实现非阻塞,需要在浏览器默认行为foucs之后执行,这里用到了setTimeout 0 ), 对input框的赋值操作---实质是对字符串进行插入或者删除的动作,点击键盘删除,需要更新光标的位置,再进行字符串的操作。
其他就是一些 比较常规的交互处理了 如点击键盘区域外关闭键盘 点击时高亮 等...
场景:针对不同人群的使用习惯 是否使用虚拟数字键盘(例:鼠标点击输入框弹出数字键盘)
参数说明:
integer:是否只显示整型 (小键盘不带小数点.) true fasle 默认false 显示小数点
方法说明:
1.showCheckBoard 展示键盘 --- 接收两个参数 e Id(input框的Id 用于给form表单赋值)例 this.onBoardRefChild.showCheckBoard(e,Id) 必须接收子组件参数event
2.setCaret 获取实时光标动态--- 例 this.onBoardRefChild.setCaret(dom) setCaret 必须接收子组件参数 input dom结构 (例:document.getElementById("xxx"))
3.setValue 显示值设置---设置最新修改的值(插入的小键盘数字或者删除后)
注意:
1.该组件需要和input框一起使用,作为input的同级元素存在 外层需要有一个共同的父元素包裹
父级元素设置相对定位 relative (便于小键盘的弹出定位)
包裹的区域为可视区域 区域外点击会关闭小键盘
2.input 必须设置一个id 例如 <Input id="inputNode" /> 用于方法函数进行元素查找和光标定位 form表单中的input id为 getFieldDecorator 设置的名字
*/
//添加点击事件 点击键盘外的区域 关闭键盘 componentDidMount() { document.addEventListener('click', this.hideKeyBoard); }
//隐藏键盘 hideKeyBoard = () => { this.setState({ showkey: false, Id: "", }) } //展示键盘 showCheckBoard = (e) => { this.stopPropagation(e); this.setState({ showkey: true, }) } //阻止冒泡事件 stopPropagation(e) { if (e && e.nativeEvent) { e.nativeEvent.stopImmediatePropagation(); } } //获取实时光标动态 setCaret = (dom) => { this.setState({ dom, }) // console.log("document.getElementById(InputId)",dom) // let obj = document.getElementById("tagsInputs") if (dom.createTextRange && dom.createTextRange) { dom.caretPos = document.selection.createRange().duplicate(); } } //插入 / 删除 内容 insertAtCaret = (textObj, textFeildValue,) => { // console.log("textObj",textObj) if (document.all) { if (textObj.createTextRange && textObj.caretPos) { var caretPos = textObj.caretPos; caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? textFeildValue + ' ' : textFeildValue; } else { textObj.value = textFeildValue; } } else { //Selection对象表示用户选择的文本范围或插入符号的当前位置。要获取用于检查或修改的Selection对象,请使用window.getSelection() // selectionSatrt记录鼠标点击的开始位置,selectionEnd记录结束位置 if (textObj.setSelectionRange) { var rangeStart = textObj.selectionStart; var rangeEnd = textObj.selectionEnd; var newLocation = textObj.selectionStart + textFeildValue.length var tempStr1 = textObj.value.substring(0, rangeStart); var tempStr2 = textObj.value.substring(rangeEnd); textObj.value = tempStr1 + (textFeildValue != "c" ? textFeildValue : "") + tempStr2; //将左边、插入值、右边拼接在一起 textObj.focus() if (textFeildValue == "c") {//删除退格操作 slice this.setState({ InputValue: ((tempStr1).slice(0, rangeEnd - 1)) + tempStr2 }, () => { this.props.setValue(this.state.InputValue, textObj.id) }) //在浏览器默认行为foucs之后执行,实现非阻塞 setTimeout(() => { textObj.setSelectionRange(rangeStart - 1, rangeStart - 1); // textObj.selectionStart = (rangeStart-1)<0?0:rangeStart-1// 更新光标位置,将之前算的新位置给输入框光标 }, 0) } else { textObj.setSelectionRange(newLocation, newLocation); this.setState({ InputValue: tempStr1 + textFeildValue + tempStr2 }, () => { this.props.setValue(this.state.InputValue, textObj.id) }) } } else { console.log("This version of Mozilla based browser does not support setSelectionRange / 此版本的基于Mozilla的浏览器不支持setSelectionRange"); } } } //点击特定内容(键盘) handleClick = (e, item) => { //点击ok关闭键盘 if(item.id=="ok"){ this.hideKeyBoard() //阻止冒泡到最外层显示键盘的按钮事件handleCheckBoard e.stopPropagation() }else{ this.insertAtCaret(this.state.dom, item.id,) } } //点击内容(键盘) handleCheckBoard = (e) => { this.showCheckBoard(e) } //高亮点击内容 handleItemMousedown = (item) => { var x = document.querySelectorAll(".number-item"); x[item.seq].style.background = '#bfbfbf'; } //还原点击内容 handleItemMouseUp = (item) => { var x = document.querySelectorAll(".number-item"); x[item.seq].style.background = '#7d7876'; } render() { const numberArr = [{ descriptsSPCode: "07", descripts: "7", id: "7", descriptsEN: "seven", seq: "0" }, { descriptsSPCode: "08", descripts: "8", id: "8", descriptsEN: "eight", seq: "1" }, { descriptsSPCode: "09", descripts: "9", id: "9", descriptsEN: "nine", seq: "2" }, { descriptsSPCode: "04", descripts: "4", id: "4", descriptsEN: "four", seq: "3" }, { descriptsSPCode: "05", descripts: "5", id: "5", descriptsEN: "five", seq: "4" }, { descriptsSPCode: "06", descripts: "6", id: "6", descriptsEN: "six", seq: "5" }, { descriptsSPCode: "01", descripts: "1", id: "1", descriptsEN: "one", seq: "6" }, { descriptsSPCode: "02", descripts: "2", id: "2", descriptsEN: "two", seq: "7" }, { descriptsSPCode: "03", descripts: "3", id: "3", descriptsEN: "three", seq: "8" }, { descriptsSPCode: "0", descripts: "0", id: "0", descriptsEN: "ten", seq: "9" }, { descriptsSPCode: "01", descripts: ".", id: ".", descriptsEN: "spot", seq: "10" }, { descriptsSPCode: "ok", descripts: "ok", id: "ok", descriptsEN: "good", seq: "11" }, { descriptsSPCode: "c", descripts: "←", id: "c", descriptsEN: "reset", seq: "12" }, ] let numberBlock = numberArr && numberArr.map((item, i) => { return ( <button className="number-item" style={{ WebkitUserSelect: "none", userSelect: "none", item.descripts == "0" && this.props.integer && this.props.integer ? "228px" : item.descripts == "0" ? "144px" : "60px", height: item.id == "c" ? "203px" : "60px", display: this.props.integer && this.props.integer && item.seq == "10" ? "none" : "inline-block", textAlign: item.descripts == "0" && !this.props.integer ? "left" : "center", paddingLeft: item.descripts == "0" && !this.props.integer ? "22px" : "0", paddingRight: "0", border: "0", lineHeight: item.id == "c" ? "203px" : "60px", borderRadius: item.id == "c" ? "0 6px 6px 0" : "4px", position: item.id == "c" ? "absolute" : "static", top: item.id == "c" ? "0px" : "0", right: item.id == "c" ? "-8px" : "0", background: "#7d7876", color: "#ffffff", cursor: "pointer", margin: item.descriptsSPCode == "ok" ? "6px 4px" : "6px 12px", fontSize: "30px", }} onClick={(e) => this.handleClick(e, item)} onMouseDown={() => this.handleItemMousedown(item)} onMouseUp={() => this.handleItemMouseUp(item)} > {item.descripts} </button> ) }) return ( <div> <div id="tags" onClick={(e) => this.handleCheckBoard(e,)} style={{ display: this.state.showkey ? "block" : "none", position: "absolute", zIndex: "1", "320px", background: "rgba(0, 0, 0, 0.65)", borderRadius: "6px", textAlign: 'left' }}> {numberBlock} </div> </div> ); }