在咱們平時的業務開發中常常會用到文案超出只有收起,點擊在展現所有文案;一般的使用時使用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} />; };
效果:
以上是本人在平時開發中使用的方式,但願對你們有所幫助,若是老鐵們有更好的方案可留言展現一下。