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

如何在Draft JS中自动聚焦新插入的原子块?

自定义Draft.js原子块插入后自动聚焦的解决方案

问题背景

已通过给定代码在Draft.js中插入自定义原子块,但尝试forceSelection、focus等方法均无法实现自动聚焦需求。


解决方案

Draft.js的原子块本身为不可编辑区块,因此需分两种场景处理自动聚焦:

场景1:聚焦到原子块后的编辑器光标位置

修改insertBlock函数,在插入原子块后,计算并设置光标到原子块后方的可编辑位置,同时手动触发编辑器聚焦:

  1. 首先给Editor组件添加ref:
import { Editor } from 'draft-js';
import { useRef } from 'react';

// 组件内定义编辑器ref
const editorRef = useRef(null);

// 渲染Editor时绑定ref
<Editor
  ref={editorRef}
  editorState={editorState}
  onChange={setEditorState}
  // 其他配置项
/>
  1. 修改insertBlock函数:
const insertBlock = () => {
  const contentState = editorState.getCurrentContent();
  const contentStateWithEntity = contentState.createEntity(
    "EDITORELEMENT",
    "MUTABLE",
    { a: "b" }
  );
  const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
  const newEditorState = EditorState.set(editorState, {
    currentContent: contentStateWithEntity
  });

  // 插入原子块
  const editorStateWithAtomicBlock = AtomicBlockUtils.insertAtomicBlock(
    newEditorState,
    entityKey,
    "text"
  );

  const updatedContent = editorStateWithAtomicBlock.getCurrentContent();
  const selection = editorStateWithAtomicBlock.getSelection();
  const blockKey = selection.getAnchorKey();
  const block = updatedContent.getBlockForKey(blockKey);

  let finalEditorState;

  // 原子块插入到区块末尾时,新建空段落并聚焦
  if (selection.getAnchorOffset() === block.getLength()) {
    const newBlock = ContentBlock.createFromText("", "unstyled");
    const newContent = updatedContent.merge({
      blockMap: updatedContent.getBlockMap().set(newBlock.getKey(), newBlock),
      selectionAfter: new SelectionState({
        anchorKey: newBlock.getKey(),
        anchorOffset: 0,
        focusKey: newBlock.getKey(),
        focusOffset: 0
      })
    });
    finalEditorState = EditorState.push(
      editorStateWithAtomicBlock,
      newContent,
      "insert-fragment"
    );
    finalEditorState = EditorState.forceSelection(
      finalEditorState,
      newContent.getSelectionAfter()
    );
  } else {
    // 原子块插入到区块中间时,直接将光标移到原子块后方
    const newSelection = selection.merge({
      anchorOffset: selection.getAnchorOffset() + 1,
      focusOffset: selection.getAnchorOffset() + 1
    });
    finalEditorState = EditorState.forceSelection(
      editorStateWithAtomicBlock,
      newSelection
    );
  }

  setEditorState(finalEditorState);
  // 延迟触发聚焦,确保DOM已更新
  setTimeout(() => {
    editorRef.current?.focus();
  }, 0);
};

场景2:聚焦原子块内部的可编辑元素

如果自定义原子块内部包含可编辑元素(如输入框),可通过ref传递在组件挂载时触发聚焦:

  1. 修改EditorElement和EditorBlock组件:
import { useEffect, useRef } from 'react';

const EditorElement: React.FC = (props: any) => {
  const editableRef = useRef<HTMLInputElement>(null);

  // 组件挂载时聚焦内部可编辑元素
  useEffect(() => {
    editableRef.current?.focus();
  }, []);

  return (
    <div className="EditorElement">
      <EditorBlock {...props} editableRef={editableRef} />
    </div>
  );
};

// 示例EditorBlock组件,包含可编辑输入框
const EditorBlock: React.FC<any> = (props) => {
  return (
    <div className="editor-block">
      <input 
        ref={props.editableRef} 
        placeholder="请输入内容"
      />
    </div>
  );
};

关键注意事项

  • Draft.js的选区更新需在DOM渲染完成后执行,因此需用setTimeout延迟触发focus方法
  • 原子块本身不可编辑,若要聚焦编辑器,必须将光标定位到可编辑的文本区块中
  • 内部可编辑元素的聚焦需确保ref正确传递,且在组件挂载生命周期触发

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 05:55:19