Skip to content

【文本溢出】JS+React自定义省略号位置

作者:江月迟迟
发表于:2025-10-29
字数统计:776 字
预计阅读3分钟

背景

如果一个很长的数据需要展示,那么需要处理文本溢出,原生CSS支持在webkit内核的浏览器调用原生的API来实现省略号在末尾的功能。然而,如果这个数据的末尾很重要(中间不重要),那么省略号的位置应该调整在中间。

适用场景

  • 需要显示文件类型
  • 需要显示文件版本号(一般版本号在末尾)
  • 需要显示文件哈希名(一般文件用哈希后缀定义唯一性)

实现

单行文本溢出,省略号在中间

tsx
const SingleEllipsisElement = ({ className, __html, value, type, suffix }) => {
  // 使用 ref 来获取 DOM 元素
  const contentRef = useRef(null);

  // 在组件加载后动态设置后缀的 left 值
  useEffect(() => {
    const contentElement = contentRef.current;
    if (contentElement) {
      const contentWidth = contentElement.offsetWidth;
      const suffixElement = contentElement.nextElementSibling; // 获取后缀 span
      const parentElement = contentElement.parentElement; // 获取父元素
      if (contentWidth < parentElement.offsetWidth) {
        suffixElement.style.opacity = 0;
        return;
      } else {
        suffixElement.style.opacity = 1;
        suffixElement.style.left = `${parentElement.offsetWidth + 13}px`;
      }
    }
  }, []);

  return (
    <div>
      {__html ? (
        <span ref={contentRef} dangerouslySetInnerHTML={{ __html }} />
      ) : (
        <span ref={contentRef}>{value}</span>
      )}
      <span style={{ position: 'absolute', left: '0' }}>{`.${suffix}`}</span>
    </div>
  );
};

多行文本溢出,省略号在中间

tsx
const MultiEllipsisElement = ({ className, __html, value, type }) => {
  const containerRef = useRef(null);

  useEffect(() => {
    const container = containerRef.current;
    if (!container) return;

    const text = __html ? container.innerHTML : value;
    const lineNum = 2; // 默认显示两行
    const { width, fontSize } = window.getComputedStyle(container);
    const containerWidth = parseFloat(width);
    const textFontSize = parseFloat(fontSize);

    const computedTextLength = (text: string) => {
      let length = 0;
      for (let i = 0; i < text.length; i++) {
        if (text.charCodeAt(i) < 0 || text.charCodeAt(i) > 255) {
          length += 2;
        } else {
          length += 1;
        }
      }
      return length;
    };

    const sliceTextLength = (text: string, sliceLength: number) => {
      let length = 0;
      let newText = '';
      for (let i = 0; i < text.length; i++) {
        if (text.charCodeAt(i) < 0 || text.charCodeAt(i) > 255) {
          length += 2;
        } else {
          length += 1;
        }
        if (length <= sliceLength) {
          newText += text[i];
        } else {
          break;
        }
      }
      return newText;
    };

    const lastSliceTextLength = (text: string, sliceLength: number) => {
      let length = 0;
      let newText = '';
      for (let i = text.length - 1; i >= 0; i--) {
        if (text.charCodeAt(i) < 0 || text.charCodeAt(i) > 255) {
          length += 2;
        } else {
          length += 1;
        }
        if (length <= sliceLength) {
          newText = text[i] + newText;
        } else {
          break;
        }
      }
      return newText;
    };

    const textLength = computedTextLength(text);
    const lineCharNum = Math.floor(containerWidth / textFontSize) * 2;
    const totalStrNum = Math.floor(lineCharNum * lineNum);

    let content = '';
    if (textLength > totalStrNum) {
      const middleIndex = Math.floor(
        totalStrNum * ((lineNum * 2 - 1) / (lineNum * 2)),
      );
      content = `${sliceTextLength(text, middleIndex - 4)}...${lastSliceTextLength(text, totalStrNum - middleIndex - 1)}`;
    } else {
      content = text;
    }
  }, []);

  return (
    <div
      ref={containerRef}
      style={{
        width: '100%',
        overflow: 'hidden',
        position: 'relative',
      }}
    >
      {__html ? (
        <div dangerouslySetInnerHTML={{ __html }} />
      ) : (
        <div>{value}</div>
      )}
    </div>
  );
};

参考资料

(大佬!)前端文本溢出打点省略展示

可能是最全的 “文本溢出截断省略” 方案合集

单行和多行都有,但是稍微有点问题。纯css实现文本中间省略

这个写的也很好。CSS 文本超出提示效果