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} />; };
效果: