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

如何将WordPress Gutenberg Popover定位到光标位置?

要实现Popover定位到RichText光标位置,同时适配全站点编辑器并替换弃用的getAnchorRect,可以通过以下方式使用最新的anchor属性:

核心修改要点

  • 弃用全局变量存储选区,改用React状态管理,避免全站点编辑器多实例冲突
  • 直接将选区的Range对象传给Popover的anchor属性(WordPress的Popover组件支持Range作为anchor参数)
  • 优化选区获取逻辑,确保在全站点编辑器环境下也能正确获取光标位置

修改后的完整代码

import { registerFormatType, toggleFormat } from '@wordpress/rich-text';
import { Fragment, useState } from '@wordpress/element';
import { BlockControls, RichTextShortcut } from '@wordpress/block-editor';
import { Popover, ToolbarButton, ToolbarGroup } from '@wordpress/components';
import { displayShortcut } from '@wordpress/keycodes';
import { __ } from '@wordpress/i18n';

const InsertMyPopup = {
    name: 'insertmypopup',
    title: __('My Popup'),
    character: 'o',
    value: '',
};

const { name, title, character } = InsertMyPopup;
const type = `my-popup/${name}`;

registerFormatType(type, {
    title,
    tagName: name,
    className: null,
    active: false,

    edit({ isActive, value, onChange, contentRef }) {
        // 使用状态存储选区Range,替代全局变量
        const [ anchorRange, setAnchorRange ] = useState(null);

        const onToggle = () => {
            // 获取当前选区
            const selection = document.defaultView.getSelection();
            const currentRange = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
            
            // 保存选区到状态
            setAnchorRange(currentRange);
            
            onChange(toggleFormat(value, { type }));
        };

        const thePopover = isActive && anchorRange && (
            <Popover
                placement='bottom-start'
                focusOnMount='firstElement'
                key='my-popover'
                expandOnMobile={true}
                headerTitle={__(
                    'My Popup',
                    'insert-my-popup'
                )}
                onClose={() => {
                    onChange(toggleFormat(value, { type }));
                    setAnchorRange(null);
                }}
                // 使用最新的anchor属性,直接传入Range对象
                anchor={anchorRange}
            >
                Popup
            </Popover>
        );

        return (
            <Fragment>
                <BlockControls group='other'>
                    <ToolbarGroup>
                        <ToolbarButton
                            icon='editor-customchar'
                            isPressed={isActive}
                            label={title}
                            onClick={onToggle}
                            shortcut={displayShortcut.primary(character)}
                        />
                    </ToolbarGroup>
                </BlockControls>
                <RichTextShortcut
                    type='primary'
                    character={character}
                    onUse={onToggle}
                    contentRef={contentRef}
                />
                {thePopover}
            </Fragment>
        );
    },
});

关键说明

  1. 状态管理替代全局变量:原来的全局anchorRange在全站点编辑器多块/多实例场景下会出现状态混乱,改用useState存储当前组件的选区,保证隔离性。
  2. 直接使用Range作为anchor:WordPress的Popover组件支持将Range对象作为anchor参数,内部会自动处理定位,比手动计算getBoundingClientRect更可靠,适配不同编辑器环境。
  3. 关闭弹窗时清空状态:在Popover的onClose回调中重置anchorRange,避免弹窗关闭后状态残留导致的异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 20:57:26