You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中如何获取contentEditable属性div的光标位置?

如何在contentEditable div中获取光标位置并插入表情

contentEditable 元素不属于 <input>/<textarea> 这类表单控件,没有 selectionStart/selectionEnd 属性,必须通过浏览器的 Selection 和 Range API 来处理光标位置和内容插入。以下是具体的解决方法和修改后的代码:

核心思路

  1. 在可编辑div失去焦点时(比如点击表情选择器),保存当前的光标/选区位置;
  2. 插入表情时,先恢复之前保存的选区,再将表情插入到对应位置;
  3. 插入后更新文本状态,并调整光标到表情后方。

修改后的完整代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 12:13:32