掘金文章归档 · 第 72 篇 CSS 布局 7/9 多行文本省略 · React 组件

控制多行文本展示,支持自定义传入行数

超过 N 行显示"展开全部",不足 N 行全部展示,不显示按钮

原文作者:随意_(掘金) | juejin.cn/post/7512650263992991782 | 发布于 2025-06-06 | 阅读 73 · 约 1 分钟

0背景

最近实现一个需求,要求一个文本容器,支持输入字符串信息:

基本的 UI 样式如下:

截图占位:超过 8 行显示省略 + 展开更多按钮的文本容器

1代码实现

import React, { useState, useRef, useEffect } from 'react';
import { memo } from 'react';

const TextExpander = ({ text, lineClamp = 8 }) => {
  const [isExpanded, setIsExpanded] = useState(false);
  const [shouldShowToggle, setShouldShowToggle] = useState(false);
  const contentRef = useRef(null);

  useEffect(() => {
    if (contentRef.current) {
      const lineHeight = parseInt(
        getComputedStyle(contentRef.current).lineHeight,
        10
      );
      const maxHeight = lineHeight * lineClamp;
      const actualHeight = contentRef.current.scrollHeight;

      setShouldShowToggle(actualHeight > maxHeight);
    }
  }, [lineClamp, text]);

  const toggleExpand = () => {
    setIsExpanded(!isExpanded);
  };

  return (
    <div className="w-full">
      <div
        ref={contentRef}
        className="break-words font-sans text-[12px] text-base leading-relaxed"
        style={
          !isExpanded && shouldShowToggle
            ? {
                display: '-webkit-box',
                WebkitLineClamp: lineClamp,
                WebkitBoxOrient: 'vertical',
                overflow: 'hidden'
              }
            : {}
        }
      >
        {text}
      </div>
      {shouldShowToggle && (
        <button
          onClick={toggleExpand}
          className="mt-2 text-[#438DFB] transition-colors duration-200 focus:outline-none"
        >
          {isExpanded ? '收起' : '展开全部'}
        </button>
      )}
    </div>
  );
};

export default memo(TextExpander);

实现要点

要点实现方式
是否超出行数getComputedStyle 取行高 × lineClamp 得到 maxHeight,与 scrollHeight 比较
省略展示-webkit-box + WebkitLineClamp + overflow: hidden
按钮显隐shouldShowToggle 为 true 才渲染"展开全部 / 收起"
受控行数lineClamp 默认 8,可自定义传入
性能优化memo 包裹,text / lineClamp 不变时不重渲染
📌 核心技巧:用 scrollHeight(实际内容高度)与 lineHeight × lineClamp(期望行数高度)比较,从而精确判断是否超行——这比纯 CSS 判断按钮显隐更可靠。

2使用

<TextExpander text={item?.content}></TextExpander>

不传 lineClamp 则默认 8 行展示。