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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 17:36:13