封装Tooltip

22 阅读1分钟

封装当内容超过一定宽度之后以省略号的形式显示,且鼠标进入元素可以查看完整内容的组件ToolTip

import { Tooltip, TooltipProps } from 'antd';
import { useState, useRef, useCallback } from 'react';

interface LazyEllipsisTooltipProps {
  content: string;
  maxWidth?: number | string;
  className?: string;
}

const LazyEllipsisTooltip = ({
  content,
  maxWidth = '100%',
  className,
  ...tooltipProps
}: LazyEllipsisTooltipProps & Omit<TooltipProps, 'title' | 'open' | 'onOpenChange'>) => {
  const textRef = useRef<HTMLDivElement>(null);
  const [tooltipOpen, setTooltipOpen] = useState(false);

  const handleMouseEnter = useCallback(() => {
    const el = textRef.current;
    if (el) {
      const isOverflowed = el.scrollWidth > el.clientWidth;
      if (isOverflowed) {
        setTooltipOpen(true);
      }
    }
  }, [content]);

  const handleMouseLeave = useCallback(() => {
    setTooltipOpen(false);
  }, []);

  return (
    <Tooltip
      title={content}
      open={tooltipOpen}
      onOpenChange={open => {
        // 防止外部意外打开
        if (open && textRef.current) {
          const isOverflowed = textRef.current.scrollWidth > textRef.current.clientWidth;
          if (!isOverflowed) return;
        }
        setTooltipOpen(open);
      }}
      mouseEnterDelay={0.3}
      mouseLeaveDelay={0.1}
      {...tooltipProps}
    >
      <div
        ref={textRef}
        className={className}
        onMouseEnter={handleMouseEnter}
        onMouseLeave={handleMouseLeave}
        style={{
          maxWidth,
          overflow: 'hidden',
          textOverflow: 'ellipsis',
          whiteSpace: 'nowrap',
          cursor: 'default',
          boxSizing: 'border-box', // 确保 padding 不影响宽度计算
        }}
      >
        {content}
      </div>
    </Tooltip>
  );
};

export  { LazyEllipsisTooltip };

使用

<LazyEllipsisTooltip content={text} placement="topLeft" maxWidth={180} />