使用React开发ToolTip文字提示组件:一行显示不下显示省略号并文字提示

         React开发项目时,显示内容一行展示不下时常常会显示省略号,此时需要鼠标放上去显示全部内容,若一行可以完全显示,只需展示即可。 

        具体的实现效果如图所示,若一行展示的下,直接展示,否则显示省略号,鼠标移入显示气泡:

        在antd Design中,已经有了ToolTip文字提示组件(文字提示 Tooltip - Ant Design),但是一行能够完全展示时,不需要文字提示,所以本文基于antd开发了ToolTip文字提示组件,核心思路是初始化组件时判断一行内容是否展示的下。

        具体做法是设置一个canvas容器,容器的宽、高和字体,将content填充到容器中并测量填充的宽度,若超过容器宽度则认为一行无法展示的下,需要注意的是,该容器透明度为0,并且设置z-index属性为-1,防止遮挡住其他内容,具体代码如下:

import React, { useState, useEffect, useRef } from "react";
import { Popover } from "antd";

// 使用canvas计算字体宽度
export const ToolTips = (props: any) => {
	const [showTooltip, setShowTooltip] = useState(-1);
	const refs = useRef();

	useEffect(() => {
		const doms = document.getElementById(props?.id || "ToolTipsId");
		const { offsetHeight, offsetWidth } = doms;
		const fontSize = getComputedStyle(doms, null).getPropertyValue("font-size");
		const fontFamily = getComputedStyle(doms, null).getPropertyValue("font-family");
		// 创建canvas标签
		const canvas = document.createElement("canvas");
		canvas.width = offsetWidth;
		canvas.height = offsetHeight;
		const ctx = canvas.getContext("2d");
		ctx.font = `${fontSize} ${fontFamily}`;
		// 获取展示的实际宽度是否超过容器宽度
		ctx.fillText(props?.content, 0, offsetHeight);
		const measureWidth = ctx.measureText(props?.content).width;
		setShowTooltip(measureWidth > offsetWidth ? 1 : 2);
	}, [props?.content]);

	return <div ref={refs} key={props?.innerKey || props?.content} style={{ position: "relative" }}>
		{
			React.cloneElement(props.children, {
				className: `${props.children?.props?.className}`,
				id: props?.id || "ToolTipsId",
				style: { opacity: 0, position: "absolute", zIndex: "-1", width: props?.width || 160 },
			})
		}
		{
			showTooltip === 1 &&
			<Popover placement="top" content={<div style={{ width: 250, fontSize: "13px", color: "#999", wordBreak: "break-all" }}>{props?.content}</div>} trigger="hover">
				{
					React.cloneElement(props.children, {
						className: `ellipsis ${props.children?.props?.className}`,
						// style: {wordBreak: "break-all" }
					})
				}
			</Popover>}
		{
			showTooltip === 2 && <>{props.children}</>
		}
	</div>;
};

        React.cloneElement函数用于复制一个和props.children一样的dom元素,用来获取children元素的宽度(offsetHeight属性)和高度(offsetWeight属性),offsetHeight和offsetWeight包含了内边距(padding)和边框(border), 并且props.children的id最好在使用数组map的时候根据index进行传值,否则页面上存在多个id=ToolTipsId时,永远取的第一个dom:

        如上图,1433800.00的宽度取的是第一列id的宽度,导致显示了气泡。当然如果不想传id,也可以在const { offsetHeight, offsetWidth } = doms这一行执行之前,取offsetWidth=props?.width。

        当显示气泡时,showToolTip值为1,默认给props.children添加ellipsis样式,让其显示省略号:index.less里的.ellipsis如下:

.ellipsis {
	width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

        调用时需要指定宽度,格式如下:

import { ToolTips } from "@src/core/components/TooltipEllipsis";

<ToolTips content={content} width="171px">
	<div className="address-area">{content}</div>
</ToolTips>

       address-area里设置了width为171px,如果不想重复设置的话,可以满足条件:
  showTooltip === 2 && <>{props.children}</>时,将<>{props.children}</>改成:

<div style={{ width: props?.width }}>{props?.children}</div>

        如果props?.children不是ReactNode类型,或者是span:

<ToolTips content={content} width="171px">
	{content}
</ToolTips>

<ToolTips content={content} width="171px">
	<span>{content}</span>
</ToolTips>

        组件里可以加一层判断:showTooltip == 2时,children不是ReactNode类型(或者判断children是string类型和number类型,即reactElement所能支持的基本类型)时外面包一层div。

        如果是span,还需设置span是display: inline-block。

        另外如果调用的地方,外部包了div,设置了样式可能会影响ToolTips,需自行调整,如:

 <div className='current-key-container'>
             
                  <ToolTips content={currentKey} width="250px">
                    <div style={{ width: "250px" }}>{currentKey}</div>
                  </ToolTips>
                  
                </div>

最后,使用Tab组件切换显示不同商品时,会复用同一块区域的DOM,此时如果ToolTip显示错误,需自行调整.

  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

heine162

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值