超过 N 行显示"展开全部",不足 N 行全部展示,不显示按钮
最近实现一个需求,要求一个文本容器,支持输入字符串信息:
基本的 UI 样式如下:
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 不变时不重渲染 |
<TextExpander text={item?.content}></TextExpander>
不传 lineClamp 则默认 8 行展示。