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

React中使用Hook结合contentEditable时按键光标重置问题排查与解决

React contentEditable光标重置问题解答

1. 光标重置的成因

每次按键触发onKeyUp事件时,你调用setHTML更新了组件state。React的机制是当state变化时会重新渲染组件,此时<pre>元素的内容会被完全替换为新的html状态值。浏览器会重新创建文本节点,原来的光标位置自然丢失,默认回到元素起始位置。这不是React的"特性",而是state更新触发重渲染后,DOM内容被替换导致的正常行为。

2. 解决方法

根据需求,有两种常见解决方案:

方案一:不依赖state实时同步内容(推荐,更简洁)

如果不需要实时把编辑内容同步到state,直接让contentEditable元素自行维护内容,仅在需要获取内容时通过ref读取:

import { useRef } from 'react';

function Dashboard() {
  const preRef = useRef(null);

  // 示例:需要获取内容时调用此方法
  const getEditedContent = () => {
    return preRef.current?.textContent || '';
  };

  return (
    <pre
      ref={preRef}
      contentEditable="true"
    >
      初始内容
    </pre>
  );
}

export default Dashboard;

方案二:实时同步state并恢复光标位置

如果必须实时将内容同步到state,需要在更新state前保存光标位置,待组件重渲染后再恢复:

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

function Dashboard() {
  const [html, setHTML] = useState("");
  const preRef = useRef(null);
  const cursorPos = useRef({ start: 0, end: 0 });

  const handleKeyUp = (e) => {
    // 保存当前光标位置
    const selection = window.getSelection();
    if (selection.rangeCount > 0) {
      const range = selection.getRangeAt(0);
      cursorPos.current = {
        start: range.startOffset,
        end: range.endOffset
      };
    }
    // 更新内容到state
    setHTML(e.currentTarget.textContent);
  };

  useEffect(() => {
    const preElement = preRef.current;
    if (!preElement || !preElement.firstChild) return;

    // 恢复光标位置
    const selection = window.getSelection();
    const range = document.createRange();
    range.setStart(preElement.firstChild, cursorPos.current.start);
    range.setEnd(preElement.firstChild, cursorPos.current.end);
    selection.removeAllRanges();
    selection.addRange(range);
  }, [html]);

  return (
    <pre
      ref={preRef}
      contentEditable="true"
      onKeyUp={handleKeyUp}
    >
      {html}
    </pre>
  );
}

export default Dashboard;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 16:53:14