React格式化SSN输入框无法使用Ctrl+A全选删除,如何修复?
SSN输入框Ctrl+A全选删除功能修复方案
问题根因
- 按键拦截逻辑未适配Mac系统的Command(Meta)键,也未放行Ctrl/Meta组合类快捷键,导致部分场景下全选操作被拦截
- 全局渲染后的光标重置逻辑强制取消了所有文本选中状态,Ctrl+A全选后立刻被重置为单个光标,无法触发批量删除
需修改的代码逻辑
- 调整
handleKeyDown按键校验规则:新增Meta键支持,且所有Ctrl/Meta组合快捷键直接放行不拦截 - 修改
useLayoutEffect光标重置逻辑:仅当用户未选中任何文本时才重置光标位置,保留用户主动选中的内容范围
完整修改后代码
import React, { useRef, useState, useLayoutEffect } from "react"; export default function App() { const [state, setState] = useState({ phone: "" }); const cursorPos = useRef(null); const inputRef = useRef(null); const keyIsDelete = useRef(false); const handleChange = (e) => { cursorPos.current = e.target.selectionStart; let val = e.target.value; cursorPos.current -= ( val.slice(0, cursorPos.current).match(/-/g) || [] ).length; let r = /(\D+)/g, first3 = "", next3 = "", last4 = ""; val = val.replace(r, ""); let newValue; if (val.length > 0) { first3 = val.substr(0, 3); next3 = val.substr(3, 2); last4 = val.substr(5, 4); if (val.length > 5) { newValue = first3 + "-" + next3 + "-" + last4; } else if (val.length > 3) { newValue = first3 + "-" + next3; } else { newValue = first3; } } else newValue = val; setState({ phone: newValue }); for (let i = 0; i < cursorPos.current; ++i) { if (newValue[i] === "-") { ++cursorPos.current; } } if (newValue[cursorPos.current] === "-" && keyIsDelete.current) { cursorPos.current++; } }; const handleKeyDown = (e) => { // 放行所有Ctrl/Meta组合快捷键,适配全选、复制、粘贴等通用操作 if (e.ctrlKey || e.metaKey) return; const allowedKeys = [ "Control", "Meta", "Delete", "ArrowLeft", "ArrowRight", "Backspace", "Home", "End", "Enter", "Tab" ]; keyIsDelete.current = e.key === "Delete"; if ("0123456789".includes(e.key) || allowedKeys.includes(e.key)) { return; } e.preventDefault(); }; useLayoutEffect(() => { if (inputRef.current) { // 仅无选中文本时重置光标,保留用户选中状态 if (inputRef.current.selectionStart === inputRef.current.selectionEnd) { inputRef.current.selectionStart = cursorPos.current; inputRef.current.selectionEnd = cursorPos.current; } } }); return ( <div className="App"> <input ref={inputRef} type="text" value={state.phone} placeholder="SSN" onChange={handleChange} onKeyDown={handleKeyDown} /> </div> ); }
内容的提问来源于stack exchange,提问作者Jon
相关产品推荐
相关产品推荐

