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

如何在Meta的Lexical编辑器中实现类浏览器的查找高亮功能?

Lexical编辑器文本匹配与无侵入高亮实现思路

核心逻辑:基于DecoratorNode的无侵入装饰

Lexical的DecoratorNode是实现该需求的核心——它允许在文档中插入可视化元素,但不会修改底层文本内容,也不会被序列化到输出结果中,完美契合“不影响文档结构”的要求。

1. 监听关键词与编辑器状态变化

  • 维护搜索关键词的状态(比如在React组件中用useState),用户输入关键词时触发匹配逻辑。
  • 订阅编辑器的update事件,每次文档内容变更时,重新扫描匹配项。

2. 遍历文档定位匹配文本

递归遍历编辑器的所有文本节点,用正则匹配关键词,记录每个匹配的节点、起始/结束偏移量:

function findMatches(keyword) {
  if (!keyword.trim()) return [];
  const matches = [];
  const regex = new RegExp(keyword, 'gi'); // 可根据需求调整大小写/全局匹配
  $getRoot().forEachDescendant(node => {
    if (node instanceof TextNode) {
      const text = node.getTextContent();
      let match;
      while ((match = regex.exec(text)) !== null) {
        matches.push({
          node,
          start: match.index,
          end: match.index + match[0].length
        });
      }
    }
  });
  return matches;
}

3. 自定义高亮装饰节点

创建继承自DecoratorNode的自定义节点,仅负责渲染高亮样式,不修改原文本:

class HighlightDecoratorNode extends DecoratorNode {
  static getType() {
    return 'highlight-decorator';
  }

  static clone(node) {
    return new HighlightDecoratorNode(node.__node, node.__start, node.__end);
  }

  constructor(node, start, end) {
    super();
    this.__node = node;
    this.__start = start;
    this.__end = end;
  }

  createDOM() {
    const span = document.createElement('span');
    span.style.backgroundColor = '#fff3cd'; // 自定义高亮样式
    span.textContent = this.__node.getTextContent().slice(this.__start, this.__end);
    return span;
  }

  updateDOM() {
    return false; // 无需更新DOM,内容变化时会重新创建节点
  }

  exportJSON() {
    return null; // 序列化时忽略该节点,不影响输出
  }
}

4. 注入装饰节点到编辑器

在编辑器更新回调中,先清除旧的高亮节点,再插入新的匹配装饰:

editor.registerUpdateListener(({editorState}) => {
  editorState.read(() => {
    // 先清除所有旧的高亮装饰节点
    $getRoot().forEachDescendant(node => {
      if (node instanceof HighlightDecoratorNode) {
        node.remove();
      }
    });

    const keyword = currentKeyword; // 这里替换为你的关键词状态
    if (!keyword) return;

    const matches = findMatches(keyword);
    matches.forEach(match => {
      const {node, start, end} = match;
      // 在匹配位置插入装饰节点
      const highlightNode = new HighlightDecoratorNode(node, start, end);
      node.splitText(start);
      const splitNode = node.splitText(end - start);
      node.insertAfter(highlightNode);
      highlightNode.insertAfter(splitNode);
    });
  });
});

5. 额外优化

  • 关键词为空时,自动清除所有高亮节点。
  • 添加“上一个/下一个”跳转功能:记录匹配项列表,通过editor.setSelection()定位到对应节点的选区。
  • 支持正则匹配的配置项(如大小写敏感、全词匹配),动态调整正则表达式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 14:45:32