Popper.js:如何使用修饰符设置位置固定策略?

Ist*_*asz 9 contextmenu css-position reactjs blueprintjs popper.js

我正在尝试使用 BlueprintJs Popover 组件实现上下文菜单;它使用 Popper.js 将弹出窗口定位在引擎盖下。

问题是:我在上下文菜单上方的 dom 树中有固定元素和绝对定位元素(将变换 css 属性设置为 translate3d - 我相信这些会创建新的堆叠上下文,也可能导致问题),无法更改。我在 Popper.js 文档中读过,在这种情况下我应该使用固定位置策略。

不幸的是 BlueprintJs Popover 不允许我(据我所知)设置 Popper.js 选项,只能设置修饰符。

那么定位策略可以通过修改器来改变吗?

这是代码和我尝试过的:

import React, { useState } from 'react';
import { Popover, Position, Classes } from '@blueprintjs/core';

const getModifiers = (left, top) => {
  return {
    preventOverflow: { boundariesElement: 'viewport' },
    computeStyle: {
      // set to false to avoid using transform property to position element,
      // as that clashes with other transform: translate3d styles set earlier
      gpuAcceleration: false,

      // I could just overwrite the computeStyles fn, and use position fixed;
      // but I'd like to avoid that and let Popper.js do the coordinate arithmetics
      // fn: (data) => {
      //   return { 
      //     ...data, 
      //     styles: { 
      //       ...data.styles, 
      //       position: 'fixed',
      //       left: `${left}px`,
      //       top: `${top}px`,
      //     }
      // };
      // },
    },

    // here's where I try to change the position strategy using custom modifier
    changeStrategyWithModifier: {
      order: 0,
      enabled: true,
      name: 'changeStrategyWithModifier',
      phase: 'main',
      fn: (data) => {
        return {
          ...data,
          instance: {
            ...data.instance,
            options: {
              ...data.instance.options,
              positionFixed: true, // does not seem ot have any effect
              strategy: 'fixed', // does not seem ot have any effect
            },
          },
          state: {
            // reset set to true to restart process after changing strategy
            ...data.instance.state,
            reset: true, 
          },
          positionFixed: true, // does not seem ot have any effect
        };
      },
    },
  };
};

const ContextMenu = (props) => {
  const [isOpen, setOpen] = useState(false);
  const [offset, setOffset] = useState();
  const portalContainer = useGetPortalContainer();

  const handleCloseContextMenu = () => setOpen(false);

  const handleInteraction = () => setOpen(false);

  const handleOpenContextMenu = (mouseEvent) => {
    mouseEvent.preventDefault();
    setOffset({ left: mouseEvent.clientX, top: mouseEvent.clientY });
    setOpen(true);
  };

  const modifiers = getModifiers(offset.left, offset.top);

  return (
    <>
      <div className={Classes.CONTEXT_MENU_POPOVER_TARGET} style={offset}>
        <Popover
          isOpen={isOpen}
          onInteraction={handleInteraction}
          content={props.renderMenu(handleCloseContextMenu)}
          target={<div />}
          usePortal={true}
          portalContainer={portalContainer}
          position={Position.TOP_LEFT}
          modifiers={modifiers}
        />
      </div>
      {props.renderComponent(handleOpenContextMenu)}
    </>
  );
};
Run Code Online (Sandbox Code Playgroud)