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
相关产品推荐
相关产品推荐

