最近在项目中有个场景是需要在textarea中获取光标位置,然后插入传入的内容,特此记录一下。UI组件库用的是antd,以下示例以react为准,vue项目类似。
记录textarea ref
...
const textAreaRef=useRef(null);
const [text,setText]=useState('');
return (
<>
<TextArea ref={textAreaRef} rows={2} value={text} onChange={handleChangeRuleText} onBlur={handleBlur} />
</>
)
定义获取光标位置的函数
export const getCursorPosition=(ctrl)=> {
let CaretPos = {
start:0,
end:0
};
if (ctrl?.resizableTextArea?.textArea.selectionStart) {
CaretPos.start = ctrl?.resizableTextArea?.textArea.selectionStart;
}
if (ctrl?.resizableTextArea?.textArea.selectionEnd) {
CaretPos.end = ctrl?.resizableTextArea?.textArea.selectionEnd;
}
return CaretPos;
}
export const setCursorPosition=(ctrl, start,end)=> {
ctrl.focus();
// ctrl.setSelectionRange(start, end); // 废弃
if (ctrl?.resizableTextArea?.textArea.selectionStart) {
ctrl.resizableTextArea.textArea.selectionStart=start;
}
if (ctrl?.resizableTextArea?.textArea.selectionEnd) {
ctrl.resizableTextArea.textArea.selectionEnd=end;
}
}
textarea内容改变以及失去焦点的时候记录光标位置
const cursorRef=useRef({
start:0,
end:0
})
const handleRecordCursorPosition=()=>{
const position = getCursorPosition(textAreaRef.current);//获取光标位置
cursorRef.current=position;
}
const handleBlur=()=>{
handleRecordCursorPosition();
}
const handleChangeRuleText=(e)=>{
setRuleText(e.target.value);
handleRecordCursorPosition();
}
外部针对textarea光标位置插入内容
const timeOutRef=useRef(null);
const handleSetRuleText=(txt='')=>{
const insertStart=cursorRef.current.start;
const insertEnd=cursorRef.current.end+txt.length;
const newText=ruleText.slice(0, insertStart) + txt + text.slice(insertStart);
timeOutRef.current=setTimeout(()=>{
setCursorPosition(textAreaRef.current,insertStart,insertEnd);
},200);
setText(newText);
}
记得清除timeout对象
useEffect(()=>{
return ()=>{
if(timeOutRef.current){
clearTimeout(timeOutRef.current);
}
}
},[])
大功告成!!!