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

React中contenteditable div光标跳转问题:如何保持光标在末尾

修复contenteditable div光标跳转及文本反向问题

你的问题根源在于每次通过innerHTML替换整个内容时,浏览器会重置光标位置到元素起始处,导致输入时光标跳开头,视觉上呈现文本反向的效果。同时当前代码的依赖逻辑存在潜在循环触发风险(若text直接取自div的innerText)。

解决方案:更新内容后手动恢复光标位置

修改useEffect逻辑,在设置新的innerHTML后,通过Range和Selection API将光标强制移到div末尾:

import { useEffect, useRef, useState } from 'react';

export default function EditableDiv() {
  const [text, setText] = useState('');
  const divRef = useRef(null);

  const handleInput = (e) => {
    setText(e.currentTarget.innerText);
  };

  useEffect(() => {
    const div = divRef.current;
    if (!div || !text) return;

    // 将文本处理为带strong标签的HTML
    const htmlArray = text.split(' ').map(word => {
      return `<strong style="color: red">${word} </strong>`;
    });
    const newHtml = htmlArray.join('');
    div.innerHTML = newHtml;

    // 定位光标到div内容末尾
    const range = document.createRange();
    const selection = window.getSelection();
    range.selectNodeContents(div);
    range.collapse(false); // false表示折叠到内容末尾
    selection.removeAllRanges();
    selection.addRange(range);
  }, [text]);

  return (
    <div
      ref={divRef}
      contentEditable
      onInput={handleInput}
      style={{ border: '1px solid #ddd', padding: '10px', minHeight: '50px' }}
    />
  );
}

关键说明

  1. 光标定位逻辑:通过document.createRange()创建选区范围,range.collapse(false)将光标折叠到内容末尾,再通过window.getSelection()设置选区,确保光标始终停在输入内容的最后。
  2. 状态依赖优化:使用独立的text状态存储输入内容,避免直接依赖div的innerText导致的无限循环更新。
  3. 文本处理细节:若不需要每个单词后额外添加空格,可调整map逻辑为${word},最后再统一处理整体空格问题。

进阶优化(可选)

如果希望光标停在用户输入的原位置(而非强制末尾),需要在更新innerHTML前记录光标相对于文本的偏移量,更新后重新计算并定位光标,这需要更复杂的选区偏移量计算逻辑。

内容的提问来源于stack exchange,提问作者Tarun

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 08:10:24