Open
Description
React文本超出指定行数显示全文,点击全文可以展开和收起
示例图片:
TextEllipsis.js
import styles from './TextEllipsis.scss';
import React, { useState, useRef, Fragment, useLayoutEffect } from 'react';
/**
* 多行文本溢出显示省略号组件
*/
const TextEllipsis = ({ content, headerText }) => {
const contentRef = useRef({});
const [showAll, setShowAll] = useState(false);
const [needHidden, setNeedHidden] = useState(false); // 超出4行需要隐藏
const [isCompute, setIsCompute] = useState(false);
/**
* @description: 处理content文案的点击展开收起
* @return: null
*/
const handleContent = e => {
e.stopPropagation();
setShowAll(!showAll);
};
// 判断文本超出行数
const isElementCollision = (ele, rowCount = 6, cssStyles, removeChild) => {
if (!ele) {
return false;
}
const clonedNode = ele.cloneNode(true);
// if(clonedNode.innerHTML){
// }
// 给clone的dom增加样式
clonedNode.style.overflow = 'visible';
clonedNode.style.display = 'inline-block';
clonedNode.style.width = 'auto';
clonedNode.style.whiteSpace = 'nowrap';
clonedNode.style.visibility = 'hidden';
clonedNode.style.whiteSpace = 'pre-wrap'; //支持换行
// 将传入的css字体样式赋值
if (cssStyles) {
Object.keys(cssStyles).forEach(item => {
clonedNode.style[item] = cssStyles[item];
});
}
// 给clone的dom增加id属性
const _time = new Date().getTime();
const containerID = `collision_node_id_${_time}`;
clonedNode.setAttribute('id', containerID);
const tmpNode = document.getElementById(containerID);
let newNode = clonedNode;
if (tmpNode) {
document.body.replaceChild(clonedNode, tmpNode);
} else {
newNode = document.body.appendChild(clonedNode);
}
// 新增的dom宽度与原dom的宽度*限制行数做对比
// 一行是25高度,根据样式TextEllipsis.scss的textContent的样式line-height: px2rem(50);
const defaulltHeight = rowCount * 25;
let differ = false;
if (newNode.offsetHeight > defaulltHeight){
differ = true;
}
if (removeChild) {
document
85E9
span>.body.removeChild(newNode);
}
return differ;
};
useLayoutEffect(() => {
const cssStyles = { fontWeight: '400' };
const needHiddenValue = isElementCollision(contentRef.current, 6, cssStyles, true);
setNeedHidden(needHiddenValue);
setIsCompute(true);
}, [contentRef]);
return (
<div className={styles.textEllipsis}>
<div style={{ opacity: isCompute ? 1 : 0 }}>
<div
ref={contentRef}
className={`${styles.textContent} ${!showAll && needHidden ? styles['hidden-text'] : ''}`}
>
{headerText ? headerText() : null}
{content}
</div>
</div>
{
!isCompute && (
<Fragment>
<div className={styles.bgLoad} />
<div className={styles.bgLoad} />
</Fragment>
)
}
{isCompute && needHidden && (
<div
className={styles['content-btn']}
onClick={e => {
handleContent(e);
}}
>
{!showAll ? '全文' : '收起'}
</div>
)}
</div>
);
};
export default TextEllipsis;
TextEllipsis.scss
.textContent {
font-size: px2rem(30);
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(0, 0, 0, 1);
line-height: px2rem(50);
word-wrap:break-word;
word-break:break-all;
white-space: pre-wrap;
}
.hidden-text {
display: -webkit-box;
-webkit-line-clamp: 6;
/*! autoprefixer: off */
-webkit-box-orient: vertical;
/* autoprefixer: on */
overflow: hidden;
}
.content-btn {
font-size: px2rem(26px);
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 600;
color: #4CCD93;
line-height: px2rem(48px);
margin-top: px2rem(10px);
}
.bgLoad{
background-image: linear-gradient(90deg, #f0f0f0 25%, #e3e3e3 37%, #f0f0f0 63%);
background-size: 400% 100%;
height: px2rem(40);
animation: loading 1.4s ease infinite;
}
.bgLoad+.bgLoad{
width: 90%;
margin-top: px2rem(12);
}
@keyframes loading {
0% {
background-position: 100% 50%
}
to {
background-position: 0 50%
}
}
使用
<TextEllipsis content={textContent} />
Metadata
Metadata
Assignees
Labels
No labels