css实现
在我们平时的业务开发中经常会用到文案超出只有收起,点击在展示全部文案;通常的使用时使用css来实现
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
效果如下:
使用css实现时只能做多行的省略,也没法根据文字去添加定制化的按钮去实现展开收起的功能,这个只是适合特定要求不是很高的场合下使用。
字符串截取
另一种方法是使用字符串截取的方案
_renderContent = item => {
const { content, id } = item;
if (content.length > 69) {
return (
<div>
<div ref={id} className="content">
{content.slice(0, 69)}
</div>
<div
className="content-btn"
ref={id + \'btn\'}
onClick={() => {
this.handleContent(item);
}}>
全文
</div>
</div>
);
} else {
return <div className="content">{content}</div>;
}
};
展示效果:
弊端:数字、中文字符和引文字符的宽度是不一样的,在使用字符串截取是很容易出现如上的偏差,并且每个手机的分辨率不一样,字符渲染的宽度像素也是不同的,这样也会导致误差;所以字符串截取也不是一种很好的方案。
最终实现方案
话不多说直接上代码:content组件
js代码:
import react from \'react\';
import cs from \'classnames\';
import \'./style.scss\';
export default class TextContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
content: props.content,
showAll: false,
btnText: \'全文\',
needHidden: false // 文字超出4行 需要隐藏
};
}
/**
* @description: 处理content文案的点击展开收起
* @return: null
*/
handleContent = e => {
e.stopPropagation();
let { showAll } = this.state;
this.setState({
showAll: !showAll
});
};
// 判断文本超出行数
isElementCollision = (ele, rowCount = 4, cssStyles, removeChild) => {
if (!ele) {
return false;
}
const clonedNode = ele.cloneNode(true);
// 给clone的dom增加样式
clonedNode.style.overflow = \'visible\';
clonedNode.style.display = \'inline-block\';
clonedNode.style.width = \'auto\';
clonedNode.style.whiteSpace = \'nowrap\';
clonedNode.style.visibility = \'hidden\';
// 将传入的css字体样式赋值
if (cssStyles) {
Object.keys(cssStyles).forEach(item => {
clonedNode.style[item] = cssStyles[item];
});
}
// 给clone的dom增加id属性
let _time = new Date().getTime();
const containerID = \'collision_node_id_\' + _time;
clonedNode.setAttribute(\'id\', containerID);
let tmpNode = document.getElementById(containerID);
let newNode = clonedNode;
if (tmpNode) {
document.body.replaceChild(clonedNode, tmpNode);
} else {
newNode = document.body.appendChild(clonedNode);
}
// 新增的dom宽度与原dom的宽度*限制行数做对比
const differ = newNode.offsetWidth - ele.offsetWidth * rowCount + 40;
// console.log(differ, \'differ\');
if (removeChild) {
document.body.removeChild(newNode);
}
return differ > 0;
};
componentDidMount = () => {
const cssStyles = { fontSize: \'0.9375rem\', fontWeight: \'400\', lineHeight: \'1.5625rem\' };
// console.log(this.isElementCollision(this.refs[\'content\'], 4, cssStyles, true));
let needHidden = this.isElementCollision(this.refs[\'content\'], 4, cssStyles, true);
this.setState({
needHidden
});
};
render() {
let { content, needHidden, showAll } = this.state;
let { headerText } = this.props;
return (
<div>
<div
ref={\'content\'}
className={cs(\'content\', { \'hidden-text\': !showAll && needHidden })}>
{headerText ? headerText() : null}
{content}
</div>
{needHidden && (
<div
className="content-btn"
onClick={e => {
this.handleContent(e);
}}>
{!showAll ? \'全文\' : \'收起\'}
</div>
)}
</div>
);
}
}
css代码:
$baseFontSize:32px !default;
// pixels to rems
@function pxToRem($px) {
@return $px / $baseFontSize * 1rem;
}
.content {
font-size: pxToRem(30px);
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(0, 0, 0, 1);
line-height: pxToRem(50px);
}
.hidden-text {
display: -webkit-box;
-webkit-line-clamp: 3;
/*! autoprefixer: off */
-webkit-box-orient: vertical;
/* autoprefixer: on */
overflow: hidden;
}
.content-btn {
font-size: pxToRem(28px);
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 600;
color: rgba(162, 116, 56, 1);
line-height: pxToRem(48px);
margin-top: pxToRem(10px);
}
引用:
import TextContainer from \'@/textContainer\';
_renderContent = item => {
const { content, id } = item;
return <TextContainer content={content} />;
};
效果: