组件-多行文本省略-展开收起

1、功能

需要实现下面的功能,多行文本出现省略,并且提供展开和收起按钮。

2、技术方案与实现

1、用-webkit-line-clamp 实现

-webkit-line-clamp 指定显示几行,然后display、overflow等等设置一下就好了。

省略号的位置非常正确,但是问题是兼容性一般,想在省略号后面加按钮就有点困难。

css 复制代码
.text {
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
}

2、用float手动实现

  1. 提供一个省略号的dom,然后设置为右浮动;
  2. text-container容器设置一个伪元素挤压文字和省略号,之后再让文字content上去(margin-top为负值)

问题:当一个单词不够显示距离时会完全消失,导致省略号和文本有很长的一段距离,可以用文本的截断解决,但是英文状态会把单词给截断,这样也不好。这个问题可以用绝对定位来解决,但是可能出现省略号遮住文字的问题。。。

代码如下:

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <style>
      .text-container {
        width: 200px;
        height: 100px;
        overflow: hidden;
      }
      .text-container::before {
        content: '';
        display: block;
        height: 80px;
      }
      .content {
        margin-top: -80px;
        line-height: 24px;
      }
      .more {
        margin-right: 10px;
        float: right;
        line-height: 1;
      }
    </style>
    <title>Document</title>
  </head>
  <body>
    <div class="text-container">
      <div class="more">...</div>
      <div class="content">
        瑟尔华润国际hi哦平台警示牌日哦和家人屁😀😍瑟尔华润国际hi哦平台警示牌日哦和家人屁😀😍瑟尔华润国际hi哦平台警示牌日哦和家人屁😀😍瑟尔华润国际hi哦平台警示牌日哦和家人屁😀😍瑟尔华润国际hi哦平台警示牌日哦和家人屁😀😍瑟尔华润国际hi哦平台警示牌日哦和家人屁😀😍瑟尔华润国际hi哦平台警示牌日哦和家人屁😀😍瑟尔华润国际hi哦平台警示牌日哦和家人屁😀😍瑟尔华润国际hi哦平台警示牌日哦和家人屁😀😍瑟尔华润国际hi哦平台警示牌日哦和家人屁😀😍瑟尔华润国际hi哦平台警示牌日哦和家人屁😀😍瑟尔华润国际hi哦平台警示牌日哦和家人屁😀😍瑟尔华润国际hi哦平台警示牌日哦和家人屁
      </div>
    </div>
  </body>
</html>

效果如下:

3、react-组件

tsx:

javascript 复制代码
import React, { memo, useEffect, useRef, useState } from 'react';
import CollapseText from './components/CollapseText';
import ExpendText from './components/ExpendText';
import styles from './index.scss';

/**
 * 可展开文本组件的Props接口
 */
interface Props {
  /** 要显示的文本内容 */
  text: string;
  /** 最大显示行数,超出后会截断显示省略号,默认为3行 */
  maxLines?: number;
  /** 自定义CSS类名 */
  className?: string;
  /** 收起按钮的文本,默认为"收起" */
  collapseText?: string | React.ReactNode;
  /** 展开按钮的文本,默认为"展开" */
  expandText?: string | React.ReactNode;
  /** 展开/收起回调 */
  onToggleExpansion?: (isExpanded: boolean) => void;
}

/**
 * 可展开文本组件
 *
 * 功能:
 * - 根据指定行数限制文本显示
 * - 超出行数时自动截断并显示展开按钮
 * - 支持展开/收起功能
 * - 支持自定义按钮文本
 *
 * @param props - 组件属性
 * @returns React函数组件
 */
const ExpandableText: React.FC<Props> = ({
  text,
  maxLines = 3,
  className = '',
  collapseText = <CollapseText />,
  expandText = <ExpendText />,
  onToggleExpansion,
}) => {
  // 控制文本是否展开的状态
  const [isExpanded, setIsExpanded] = useState(false);
  // 标记文本是否需要展开功能(即是否超出了指定行数)
  const [needsExpansion, setNeedsExpansion] = useState(false);
  // 文本容器的DOM引用,用于计算文本高度
  const textRef = useRef<HTMLDivElement>(null);
  const [peerContainerHeight, setPeerContainerHeight] = useState(0);
  const [containerHeight, setContainerHeight] = useState(0);
  /**
   * 检测文本是否超出指定的行数
   * 通过比较实际内容高度和最大允许高度来判断
   */
  useEffect(() => {
    if (textRef.current) {
      // 获取当前元素的行高
      const lineHeight = parseInt(getComputedStyle(textRef.current).lineHeight);
      // 计算指定行数对应的最大高度
      const maxHeight = lineHeight * maxLines;
      setPeerContainerHeight(maxHeight);
      setContainerHeight(maxHeight);
      // 获取实际内容的滚动高度(包含被隐藏的部分)
      const actualHeight = textRef.current.scrollHeight;
      // 如果实际高度超过最大高度,则需要展开功能
      setNeedsExpansion(actualHeight > maxHeight);
    }
  }, [text, maxLines]); // 当文本内容或最大行数改变时重新检测

  /**
   * 切换文本展开/收起状态
   * @param e - 鼠标点击事件
   */
  const toggleExpansion = (e: React.MouseEvent<HTMLButtonElement>) => {
    // 阻止事件冒泡,避免触发父级元素的点击事件
    e.stopPropagation();
    const newIsExpanded = !isExpanded;
    // 切换展开状态
    setIsExpanded(newIsExpanded);
    onToggleExpansion?.(newIsExpanded);
    // 切换展开状态时,更新容器高度
    if (newIsExpanded) {
      setContainerHeight(textRef.current?.clientHeight || containerHeight);
    } else {
      setContainerHeight(peerContainerHeight);
    }
  };

  return (
    <div
      className={`${styles['text-container']} ${className}`}
      style={
        {
          '--container-height': `${containerHeight}px`,
          '--line-height': `${24}px`,
        } as React.CSSProperties
      }
    >
      {needsExpansion && (
        // <span className={isExpanded ? styles.more : styles['more-position-expend']}>
        <span className={styles['more']}>
          {!isExpanded && <span className={styles['more-text']}>... </span>}
          <span className={styles['more-button']} onClick={toggleExpansion}>
            {isExpanded ? collapseText : expandText}
          </span>
        </span>
      )}
      <div ref={textRef} className={`${styles['content']}`}>
        {text}
      </div>
    </div>
  );
};

export default memo(ExpandableText);

css:

javascript 复制代码
.text-container {
  height: var(--container-height);
  overflow: hidden;
  position: relative;
}
.text-container::before {
  content: '';
  display: block;
  height: calc(var(--container-height) - var(--line-height, 24px));
}

.content {
  margin-top: calc((var(--container-height) - var(--line-height, 24px)) * -1);
  line-height: var(--line-height, 24px);
}
.more-position-expend {
  padding-left: 10px;
  position: absolute;
  bottom: 4px;
  right: 0;
  background: white;
}
.more {
  float: right;
  line-height: var(--line-height, 24px);
}
.more-text {
  font-size: 16px;
}
.more-button {
  margin-left: 4px;
  cursor: pointer;
  color: rgb(255, 34, 102);
}

3、END

目前采用float的方式

相关推荐
拉不动的猪31 分钟前
前端小白之 CSS弹性布局基础使用规范案例讲解
前端·javascript·css
伍哥的传说36 分钟前
React强大且灵活hooks库——ahooks入门实践之开发调试类hook(dev)详解
前端·javascript·react.js·ecmascript·hooks·react-hooks·ahooks
界面开发小八哥1 小时前
界面控件Kendo UI for Angular 2025 Q2新版亮点 - 增强跨设备的无缝体验
前端·ui·界面控件·kendo ui·angular.js
枷锁—sha2 小时前
从零掌握XML与DTD实体:原理、XXE漏洞攻防
xml·前端·网络·chrome·web安全·网络安全
F2E_Zhangmo2 小时前
基于cornerstone3D的dicom影像浏览器 第二章,初始化页面结构
前端·javascript·vue·cornerstone3d·cornerstonejs
代码的余温2 小时前
如何区别HTML和HTML5?
前端·html·html5
天下无贼!2 小时前
【样式效果】纯CSS从零到一实现动态彩色背景效果
前端·css
DoraBigHead2 小时前
手写 `new`、`call`、`apply`、`bind` + V8 函数调用机制解密
前端·javascript·面试
_pengliang2 小时前
css 音频波浪动画-小程序\PC可用
前端·css·小程序
ai小鬼头3 小时前
AIStarter教你快速打包GPT-SoVITS-v2,解锁AI应用市场新玩法
前端·后端·github