先上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", width: 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", width: "320px", background: "rgba(0, 0, 0, 0.65)", borderRadius: "6px", textAlign: 'left' }}> {numberBlock} </div> </div> ); }