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

