Tiptap结合Tippy实现固定气泡菜单异常问题求助
问题
我想用Tippy给ProseMirror节点实现固定气泡菜单。最初尝试用<BubbleMenu>扩展,但发现光标在菜单内移动时菜单会随之移位,于是改为将<NodeView>包裹在<Tippy>组件中。但新问题出现:点击按钮边缘功能正常,但点击按钮中间的图标时,按钮不会高亮激活,且光标位置会发生异常变动。无论节点下方是否有段落,按钮激活失败的问题都存在,且下方有段落时光标位置错乱的情况更明显。
相关代码
function PanelBubbleMenuContent({ editor }: { editor: any }) { return ( <span> <div role="menu"> <div className="mw-panel-bubble-menu d-flex ai-center"> <button type="button" className="flex--item s-btn mr4" title="" onClick={() => { editor .chain() .focus() .updateAttributes("panel", { panelType: PanelType.INFO, }) .run(); }} > <InfoIcon color={getIconColor(PanelType.INFO)} /> </button> <button type="button" className="flex--item s-btn mr4" title="" onClick={() => { editor .chain() .focus() .updateAttributes("panel", { panelType: PanelType.NOTE, }) .run(); }} > {" "} <NoteIcon color={getIconColor(PanelType.NOTE)} /> </button> <button type="button" className="flex--item s-btn mr4" title="" onClick={() => { editor .chain() // .focus() .updateAttributes("panel", { panelType: PanelType.SUCCESS, }) .run(); }} > <SuccessIcon color={getIconColor(PanelType.SUCCESS)} /> </button> <button type="button" className="flex--item s-btn mr4" title="" onClick={() => { editor .chain() // .focus() .updateAttributes("panel", { panelType: PanelType.WARNING, }) .run(); }} > <WarningIcon color={getIconColor(PanelType.WARNING)} /> </button> <button type="button" className="flex--item s-btn mr4" title="" onClick={() => { editor .chain() // .focus() .updateAttributes("panel", { panelType: PanelType.ERROR, }) .run(); }} > <ErrorIcon color={getIconColor(PanelType.ERROR)} /> </button> <button type="button" className="flex--item s-btn mr4" title="" onClick={() => { editor.chain().deleteNode("panel").run(); }} > <TrashIcon /> </button> </div> </div> </span> ); } export function PanelNodeView({ editor, node, updateAttributes, deleteNode, }: NodeViewProps) { return ( <Tippy className="mw-popover" trigger="click" animation="shift-toward-subtle" hideOnClick={false} content={<PanelBubbleMenuContent editor={editor} />} interactive={true} placement="bottom" onClickOutside={(instance) => { instance.hide(); }} > <NodeViewWrapper as="div" className="mw-panel" data-panel-type={node.attrs.panelType} style={{ backgroundColor: getColor(node.attrs.panelType) }} > <div className="mw-panel--icon" contentEditable={false} style={{ color: getIconColor(node.attrs.panelType) }} > {getIcon(node.attrs.panelType)} </div> <NodeViewContent className="mw-panel--content" /> </NodeViewWrapper> </Tippy> ); }
解决方案
1. 让图标点击穿透到按钮
图标默认会捕获点击事件,导致按钮无法触发激活状态。给所有图标添加pointer-events: none样式,让点击直接穿透到父级按钮:
.mw-panel-bubble-menu button > svg { pointer-events: none; }
如果是自定义Icon组件,也可以直接在组件内部设置:
function InfoIcon({ color }) { return ( <svg style={{ pointerEvents: 'none', color }}> {/* 图标内容 */} </svg> ); }
2. 阻止按钮mousedown事件的默认行为
点击按钮时,ProseMirror的mousedown事件会自动修改编辑器选区并移动光标。给所有按钮添加mousedown处理,阻止默认行为:
<button type="button" className="flex--item s-btn mr4" title="" onMouseDown={(e) => e.preventDefault()} onClick={() => { editor .chain() .focus() .updateAttributes("panel", { panelType: PanelType.INFO, }) .run(); }} > <InfoIcon color={getIconColor(PanelType.INFO)} /> </button>
3. 恢复所有按钮的.focus()调用
之前部分按钮注释掉了.focus(),会导致编辑器状态不一致。恢复所有按钮的editor.chain().focus()调用,确保操作时编辑器处于正确的聚焦状态。
完成以上修改后,点击图标会触发按钮的激活状态,同时光标位置不会再异常变动。
内容的提问来源于stack exchange,提问作者Mercer
相关产品推荐
相关产品推荐

