@alifd/next Balloon 组件有一个小问题,当trigger位于屏幕边缘时,弹出窗的小箭头指向就不一定能够正确指向trigger了,如下图:trigger4触发的弹窗,小箭头固定显示在弹出窗中间,因为弹出窗右侧紧贴屏幕边缘,小箭头指向就会错位。

alt

修复

BalloonAlt组件

import { Balloon } from "@alifd/next";
import { BalloonProps } from '@alifd/next/types/balloon'
import styles from './index.module.scss'
import { cloneElement, useEffect, useRef, useState } from "react";
import { findDOMNode } from "react-dom";

const BalloonAlt = (props:BalloonProps) => {
  const { children, popupClassName, popupStyle, trigger } = props;
  const triggerRef = useRef({})
  const [ ballonStyleVars, setBallonStyleVars ] = useState({})

  useEffect(() => {
    const DOMInsertObserve = new MutationObserver(entris => {
      entris.forEach(entry => {
        const { classList } = entry.target as HTMLElement
        if ([...classList].includes(styles['balloon-alt'])) {
          updateBallonStyleVars()
        }
      })
      
    })
    DOMInsertObserve.observe(document.documentElement, {attributes: true, subtree: true})

    // 监听resize事件
    window.addEventListener("resize", updateBallonStyleVars)
    return () => {
      DOMInsertObserve.disconnect()
      window.removeEventListener("resize", updateBallonStyleVars)
    }
  }, [])

  const updateBallonStyleVars = () => {
    const triggerNode = findDOMNode((trigger.ref || triggerRef).current) as HTMLElement
    const popupNode = document.getElementsByClassName(styles['balloon-alt'])[0] as HTMLElement
    const left = triggerNode?.offsetLeft + triggerNode?.offsetWidth/2 - popupNode?.offsetLeft

    if (left) {
      setBallonStyleVars({
        '--ballon-alt-arrow-left': left+'px'
      })
    }
    
  }

  return <Balloon
    {...props}
    trigger={cloneElement(trigger, { 
      ref: trigger.ref || triggerRef
    })}
    popupClassName={`${styles['balloon-alt']} ${popupClassName ?? ''}`}
    popupStyle={{ ...ballonStyleVars, ...(popupStyle ?? {}) }}
  >
    {children}
  </Balloon>
}

export default BalloonAlt

样式文件

.balloon-alt {
  &::after {
    left: var(--ballon-alt-arrow-left, 50%) !important;
    transform: translateX(-50%) rotate(45deg);
  }
}