如何自定义Lexical.js的FORMAT_TEXT_COMMAND实现字体族设置
问题解答
核心结论
不支持直接扩展内置的FORMAT_TEXT_COMMAND传入字体参数实现字体切换。
这个命令的内置处理逻辑、可接收的payload值是Lexical核心写死的,默认只识别bold/italic/underline/strikethrough/code/subscript/superscript这几个内置文本格式,传入Arial这类字体名不会被识别处理,甚至可能触发类型报错。
对齐加粗/斜体逻辑的字体切换实现方案
你要实现「给选中文本包裹带font-family内联样式的标签、支持点击切换开关、和内置格式行为一致」的效果,按照Lexical的扩展规范走自定义节点+自定义命令的路径即可,实现逻辑和内置文本格式完全同源:
- 扩展自定义文本节点
基于内置TextNode派生专属的字体文本节点,新增fontFamily属性,重写DOM渲染逻辑给输出的DOM节点加对应内联样式,同时补全JSON序列化、DOM导入导出方法,保证复制粘贴、内容保存解析正常。
参考代码:import { TextNode, $applyNodeReplacement } from 'lexical'; export class FontFamilyTextNode extends TextNode { static getType() { return 'font-family-text'; } static clone(node) { return new FontFamilyTextNode(node.__text, node.__fontFamily, node.__key); } constructor(text, fontFamily = undefined, key) { super(text, key); this.__fontFamily = fontFamily; } createDOM(config) { const dom = super.createDOM(config); if (this.__fontFamily) { dom.style.fontFamily = this.__fontFamily; } return dom; } updateDOM(prevNode, dom) { const baseUpdated = super.updateDOM(prevNode, dom); if (prevNode.__fontFamily !== this.__fontFamily) { dom.style.fontFamily = this.__fontFamily || ''; return true; } return baseUpdated; } setFontFamily(fontFamily) { const self = this.getWritable(); self.__fontFamily = fontFamily; return this; } getFontFamily() { return this.getLatest().__fontFamily; } // 按需补全exportJSON、importJSON、importDOM方法即可 } // 初始化编辑器时,把这个节点传入editor配置的nodes数组中 export function $createFontFamilyTextNode(text, fontFamily) { return $applyNodeReplacement(new FontFamilyTextNode(text, fontFamily)); } - 定义专属字体格式命令
不要复用内置的FORMAT_TEXT_COMMAND,单独创建字体切换命令:import { createCommand } from 'lexical'; export const FORMAT_FONT_FAMILY_COMMAND = createCommand('FORMAT_FONT_FAMILY_COMMAND'); - 注册命令处理逻辑
在编辑器初始化完成后注册命令,处理逻辑和内置加粗/斜体的逻辑完全一致:获取当前选区,遍历选中的文本节点,切换节点的fontFamily属性,已经是目标字体就移除样式实现开关效果。
参考代码:import { $getSelection, $isRangeSelection, $isTextNode, COMMAND_PRIORITY_EDITOR } from 'lexical'; editor.registerCommand( FORMAT_FONT_FAMILY_COMMAND, (targetFontFamily) => { const selection = $getSelection(); if (!$isRangeSelection(selection)) return false; selection.getNodes().forEach(node => { if ($isTextNode(node)) { // 普通TextNode可先替换为自定义字体节点再设置属性 let targetNode = node; if (!(node instanceof FontFamilyTextNode)) { targetNode = $createFontFamilyTextNode(node.getTextContent(), undefined); node.replace(targetNode); } if (targetNode.getFontFamily() === targetFontFamily) { targetNode.setFontFamily(undefined); } else { targetNode.setFontFamily(targetFontFamily); } } }); return true; }, COMMAND_PRIORITY_EDITOR ); - 工具栏按钮派发自定义命令
把你原来按钮里派发的命令换成自定义的字体命令即可:<button onClick={() => { editor.dispatchCommand(FORMAT_FONT_FAMILY_COMMAND, 'Arial'); }} > Arial </button>
如果你不想从零写整套逻辑,可以直接用官方生态里
@lexical/rich-text提供的内置字体格式能力,已经封装好了节点、命令和工具栏逻辑,行为和加粗、斜体等内置格式完全一致。
内容的提问来源于stack exchange,提问作者vince852
相关产品推荐
相关产品推荐

