react 实现textarea获取光标位置在光标处插入文字

4,726 阅读1分钟

最近在项目中有个场景是需要在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);
        }
    }
},[])

大功告成!!!