Lexical中如何识别旧数据占位符并转换为自定义PlaceholderNode?
解决Lexical中旧数据占位符识别问题的标准方案
核心思路
要同时兼容新数据(带标识span的占位符)和旧数据(纯文本格式的{Placeholder Name}),需要分两部分处理:自定义节点的DOM导入导出逻辑,以及文本节点的后置转换处理。
1. 完善PlaceholderNode的基础实现
首先确保自定义节点本身能正确处理DOM的导入导出,覆盖新数据的场景:
import { TextNode } from 'lexical'; export class PlaceholderNode extends TextNode { static getType() { return 'placeholder'; } static clone(node) { return new PlaceholderNode(node.__text, node.__key); } constructor(text, key) { super(text, key); this.setMode('segmented').toggleDirectionless(); } createDOM(config) { const dom = super.createDOM(config); dom.className = 'placeholder-node'; // 你的占位符标识类 return dom; } updateDOM(prevNode, dom, config) { const update = super.updateDOM(prevNode, dom, config); if (prevNode.__text !== this.__text) { dom.textContent = this.__text; } return update; } // 识别带标识类的span(新数据场景) static importDOM() { return { span: (domNode) => { if (domNode.classList.contains('placeholder-node')) { return { conversion: (node) => new PlaceholderNode(node.getTextContent()), priority: 1, // 优先级高于普通文本节点,确保优先识别 }; } return null; }, }; } // 导出时自动添加标识span(保证新数据格式统一) exportDOM() { const dom = super.exportDOM(); dom.element.className = 'placeholder-node'; return dom; } }
2. 注册文本节点转换逻辑(处理旧数据)
Lexical导入HTML时会先把所有内容转为基础文本节点,我们通过registerNodeTransform扫描文本内容,将符合{...}格式的片段替换为PlaceholderNode:
import { $isTextNode, registerNodeTransform } from 'lexical'; // 在编辑器初始化时注册转换逻辑 editor.registerNode(PlaceholderNode); registerNodeTransform(TextNode, (textNode) => { const fullText = textNode.getTextContent(); // 正则匹配你的占位符格式,可根据实际需求调整 const placeholderRegex = /\{([^}]+)\}/g; let matchResult; let lastPosition = 0; const newNodes = []; // 拆分文本为普通文本+占位符节点 while ((matchResult = placeholderRegex.exec(fullText)) !== null) { const preText = fullText.slice(lastPosition, matchResult.index); if (preText) { newNodes.push(new TextNode(preText)); } newNodes.push(new PlaceholderNode(matchResult[0])); lastPosition = matchResult.index + matchResult[0].length; } // 添加剩余的普通文本 if (lastPosition < fullText.length) { newNodes.push(new TextNode(fullText.slice(lastPosition))); } // 替换原文本节点 if (newNodes.length > 1) { textNode.replace(...newNodes); } else if (newNodes.length === 1 && !$isTextNode(newNodes[0])) { textNode.replace(newNodes[0]); } });
关键注意事项
- 正则表达式需匹配你的占位符格式,比如如果允许占位符内包含特殊字符,要调整正则规则。
- 转换逻辑会在每次HTML导入后自动执行,无需额外调用。
- 确保
PlaceholderNode的优先级设置正确,避免和其他自定义节点冲突。
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

