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

LexicalJS文本编辑器:如何实现点击按钮添加内容功能

LexicalJS点击外部元素向编辑器插入内容的实现方案

你的代码核心问题有两个:一是未正确获取Editor实例(useLexicalComposerContext被注释,且调用位置不在LexicalComposer上下文范围内);二是插入逻辑没有考虑光标位置(直接追加到根节点,而非用户当前选中位置)。以下是修正后的完整实现方案:

修正后的完整代码

import {$getRoot, $getSelection, $createParagraphNode, $createTextNode} from 'lexical';
import { LexicalComposer } from "@lexical/react/LexicalComposer";
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin";
import { AutoFocusPlugin } from "@lexical/react/LexicalAutoFocusPlugin";
import LexicalErrorBoundary from "@lexical/react/LexicalErrorBoundary";
import TreeViewPlugin from "./editor/TreeViewPlugin";
import ToolbarPlugin from "./editor/ToolbarPlugin";
import { HeadingNode, QuoteNode } from "@lexical/rich-text";
import { TableCellNode, TableNode, TableRowNode } from "@lexical/table";
import { ListItemNode, ListNode } from "@lexical/list";
import { CodeHighlightNode, CodeNode } from "@lexical/code";
import { AutoLinkNode, LinkNode } from "@lexical/link";
import { LinkPlugin } from "@lexical/react/LexicalLinkPlugin";
import { ListPlugin } from "@lexical/react/LexicalListPlugin";
import { MarkdownShortcutPlugin } from "@lexical/react/LexicalMarkdownShortcutPlugin";
import { TRANSFORMERS } from "@lexical/markdown";
import {OnChangePlugin} from '@lexical/react/LexicalOnChangePlugin';
import ListMaxIndentLevelPlugin from "./editor/ListMaxIndentLevelPlugin";
import CodeHighlightPlugin from "./editor/CodeHighlightPlugin";
import AutoLinkPlugin from "./editor/AutoLinkPlugin";
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';

const editorConfig = {
    onError(error) {
      throw error;
    },
    nodes: [
      HeadingNode,
      ListNode,
      ListItemNode,
      QuoteNode,
      CodeNode,
      CodeHighlightNode,
      TableNode,
      TableCellNode,
      TableRowNode,
      AutoLinkNode,
      LinkNode
    ]
};

function onChange(editorState) {
    editorState.read(() => {
      const root = $getRoot();
      console.log(root.getTextContent());
    });
}

// 封装插入按钮组件,确保在Lexical上下文内获取Editor实例
const InsertButton = () => {
  const [editor] = useLexicalComposerContext();

  const addStuff = () => {
    editor.update(() => {
      const selection = $getSelection();
      if (selection) {
        // 方案1:直接在光标位置插入纯文本
        selection.insertText("点击插入的文本内容");

        // 方案2:插入带格式的段落节点(示例:加粗文本)
        // const paragraph = $createParagraphNode();
        // const text = $createTextNode("带格式的插入内容");
        // text.format('bold', true);
        // paragraph.append(text);
        // selection.insertNodes([paragraph]);
      } else {
        // 若没有选中区域,追加到编辑器末尾
        const root = $getRoot();
        const paragraph = $createParagraphNode();
        paragraph.append($createTextNode("默认追加到末尾的内容"));
        root.append(paragraph);
      }
    });
  };

  return <div onClick={addStuff} style={{cursor: 'pointer', padding: '8px', border: '1px solid #ccc', marginBottom: '10px'}}>点击我向编辑器添加内容</div>;
};

const MyEditor = () => {
  return (
    <LexicalComposer initialConfig={editorConfig}>
      {/* 插入按钮放在LexicalComposer内部,确保能获取上下文 */}
      <InsertButton />
      <div className="editor-container">
        <ToolbarPlugin />
        <div className="editor-inner">
          <RichTextPlugin
            contentEditable={<ContentEditable className="editor-input" />}
            placeholder={<div className="editor-placeholder">Enter your text...</div>}
            ErrorBoundary={LexicalErrorBoundary}
          />
          <HistoryPlugin />
          <TreeViewPlugin />
          <AutoFocusPlugin />
          <CodeHighlightPlugin />
          <ListPlugin />
          <LinkPlugin />
          <AutoLinkPlugin />
          <ListMaxIndentLevelPlugin maxDepth={7} />
          <MarkdownShortcutPlugin transformers={TRANSFORMERS} />
          <OnChangePlugin onChange={onChange} />
        </div>
      </div>
    </LexicalComposer>
  );
};

export default MyEditor;

核心实现思路

  • 正确获取Editor实例:useLexicalComposerContext必须在LexicalComposer的子组件中调用,因此将插入按钮封装成独立组件并放在Composer内部,确保能获取到编辑器实例。
  • 分场景处理插入逻辑:优先在用户光标选中位置插入内容(调用insertText或insertNodes),无选中区域时则追加到编辑器末尾,符合常规交互预期。
  • 遵循Lexical更新规则:所有内容修改操作必须放在editor.update()回调中,由Lexical自动处理状态同步和DOM更新,避免手动操作DOM引发的异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 01:22:50