在咱们平时的业务开发中常常会用到文案超出只有收起,点击在展现所有文案;一般的使用时使用css来实现css
display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
效果以下: node
使用css实现时只能作多行的省略,也无法根据文字去添加定制化的按钮去实现展开收起的功能,这个只是适合特定要求不是很高的场合下使用。react
另外一种方法是使用字符串截取的方案web
_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>; } };
展现效果:app
弊端: dom
数字、中文字符和引文字符的宽度是不同的,在使用字符串截取是很容易出现如上的误差,而且每一个手机的分辨率不同,字符渲染的宽度像素也是不一样的,这样也会致使偏差;因此字符串截取也不是一种很好的方案。字体
话很少说直接上代码:content组件 this
js代码:spa
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代码:3d
$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} />; };
效果:
以上是本人在平时开发中使用的方式,但愿对你们有所帮助,若是老铁们有更好的方案可留言展现一下。