React中如何获取contentEditable属性div的光标位置?
如何在contentEditable div中获取光标位置并插入表情
contentEditable 元素不属于 <input>/<textarea> 这类表单控件,没有 selectionStart/selectionEnd 属性,必须通过浏览器的 Selection 和 Range API 来处理光标位置和内容插入。以下是具体的解决方法和修改后的代码:
核心思路
- 在可编辑div失去焦点时(比如点击表情选择器),保存当前的光标/选区位置;
- 插入表情时,先恢复之前保存的选区,再将表情插入到对应位置;
- 插入后更新文本状态,并调整光标到表情后方。
修改后的完整代码
import { useRef, useState } from 'react'; const EmojiEditor = () => { const inputRef = useRef(null); const [text, setText] = useState(''); const [savedRange, setSavedRange] = useState(null); const handleInput = (event) => setText(event.target.textContent); // 失去焦点时保存当前选区 const handleBlur = () => { const selection = window.getSelection(); if (selection.rangeCount > 0) { setSavedRange(selection.getRangeAt(0)); } }; const handleInsertEmoji = ({ native: emoji }) => { const editableDiv = inputRef.current; if (!editableDiv) return; editableDiv.focus(); const selection = window.getSelection(); // 恢复之前保存的光标位置 if (savedRange) { selection.removeAllRanges(); selection.addRange(savedRange); } // 创建表情文本节点并插入到光标处 const emojiNode = document.createTextNode(emoji); const range = selection.getRangeAt(0); range.deleteContents(); // 若需要替换选中内容则保留,否则可移除 range.insertNode(emojiNode); // 将光标移动到表情后方 range.setStartAfter(emojiNode); range.setEndAfter(emojiNode); selection.removeAllRanges(); selection.addRange(range); // 更新文本状态 setText(editableDiv.textContent); }; return ( <div> <div ref={inputRef} contentEditable={true} onInput={handleInput} onBlur={handleBlur} style={{ border: '1px solid #ccc', padding: '8px', minHeight: '40px' }} /> <EmojiPicker onEmojiSelect={handleInsertEmoji} /> </div> ); }; export default EmojiEditor;
关键API说明
window.getSelection():获取当前页面的选区对象,包含光标或选中的内容信息;selection.getRangeAt(0):获取选区中的第一个Range对象,Range代表文档中的一段连续区域;range.insertNode(node):在Range指定的位置插入DOM节点;range.setStartAfter(node)/range.setEndAfter(node):调整Range的位置到目标节点后方,用于移动光标。
内容的提问来源于stack exchange,提问作者Epple
相关产品推荐
相关产品推荐

