Commit b6570f15 authored by nikogu's avatar nikogu

use -webkit-line-clamp & remove cover mode

parent d04c138e
---
order: 2
title: 按照行数省略的覆盖后缀模式
---
通过设置 `lines` 属性指定最大行数,如果超过这个行数的文本会自动截取。通过设置 `cover` 属性设置后缀的覆盖模式,在这种模式下可以在 `children` 中使用 `ReactNode`
但是因为是覆盖形式的后缀,可能需要通过 `suffixOffset` 以及 `suffixColor` 来设置 `...` 的样式以修正。
````jsx
import Ellipsis from 'ant-design-pro/lib/Ellipsis';
const article = <p>There were injuries alleged in three <a href="#cover">cases in 2015</a>, and a fourth incident in September, according to the safety recall report. After meeting with US regulators in October, the firm decided to issue a voluntary recall.</p>;
ReactDOM.render(
<div style={{ width: 200 }}>
<Ellipsis lines={3} cover>{article}</Ellipsis>
<h4 style={{ marginTop: 24 }}>Using SuffixOffset</h4>
<Ellipsis lines={3} cover suffixOffset={4}>{article}</Ellipsis>
</div>
, mountNode);
````
...@@ -14,7 +14,7 @@ const article = <p>There were injuries alleged in three <a href="#cover">cases i ...@@ -14,7 +14,7 @@ const article = <p>There were injuries alleged in three <a href="#cover">cases i
ReactDOM.render( ReactDOM.render(
<div style={{ width: 200 }}> <div style={{ width: 200 }}>
<Ellipsis lines={3}>{article}</Ellipsis> <Ellipsis tooltip lines={3}>{article}</Ellipsis>
</div> </div>
, mountNode); , mountNode);
```` ````
...@@ -6,6 +6,8 @@ import styles from './index.less'; ...@@ -6,6 +6,8 @@ import styles from './index.less';
/* eslint react/no-did-mount-set-state: 0 */ /* eslint react/no-did-mount-set-state: 0 */
/* eslint no-param-reassign: 0 */ /* eslint no-param-reassign: 0 */
const isSupportLineClamp = (document.body.style.webkitLineClamp !== undefined);
const EllipsisText = ({ text, length, tooltip, ...other }) => { const EllipsisText = ({ text, length, tooltip, ...other }) => {
if (typeof text !== 'string') { if (typeof text !== 'string') {
throw new Error('Ellipsis children must be string.'); throw new Error('Ellipsis children must be string.');
...@@ -22,7 +24,7 @@ const EllipsisText = ({ text, length, tooltip, ...other }) => { ...@@ -22,7 +24,7 @@ const EllipsisText = ({ text, length, tooltip, ...other }) => {
} }
if (tooltip) { if (tooltip) {
return <span>{displayText}<Tooltip title={text}>{tail}</Tooltip></span>; return <Tooltip title={text}><span>{displayText}{tail}</span></Tooltip>;
} }
return ( return (
...@@ -34,35 +36,25 @@ const EllipsisText = ({ text, length, tooltip, ...other }) => { ...@@ -34,35 +36,25 @@ const EllipsisText = ({ text, length, tooltip, ...other }) => {
export default class Ellipsis extends Component { export default class Ellipsis extends Component {
state = { state = {
lineHeight: 0,
text: '', text: '',
targetCount: 0, targetCount: 0,
} }
componentDidMount() { componentDidMount() {
const { lines, cover } = this.props;
if (this.node) { if (this.node) {
if (lines && cover) {
this.setState({
lineHeight: parseInt(window.getComputedStyle(this.node).lineHeight, 10),
});
}
this.computeLine(); this.computeLine();
} }
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if (this.props.lines !== nextProps.lines || this.props.cover !== nextProps.cover) { if (this.props.lines !== nextProps.lines) {
this.setState({
lineHeight: parseInt(window.getComputedStyle(this.node).lineHeight, 10),
});
this.computeLine(); this.computeLine();
} }
} }
computeLine = () => { computeLine = () => {
const { lines, cover } = this.props; const { lines } = this.props;
if (lines && !cover) { if (lines && !isSupportLineClamp) {
const fontSize = parseInt(window.getComputedStyle(this.node).fontSize, 10) || 14; const fontSize = parseInt(window.getComputedStyle(this.node).fontSize, 10) || 14;
const text = this.shadowChildren.innerText; const text = this.shadowChildren.innerText;
const targetWidth = (this.node.offsetWidth || this.node.parentNode.offsetWidth) * lines; const targetWidth = (this.node.offsetWidth || this.node.parentNode.offsetWidth) * lines;
...@@ -128,22 +120,20 @@ export default class Ellipsis extends Component { ...@@ -128,22 +120,20 @@ export default class Ellipsis extends Component {
} }
render() { render() {
const { text, targetCount, lineHeight } = this.state; const { text, targetCount } = this.state;
const { const {
children, children,
lines, lines,
length, length,
cover = false,
suffixColor = '#fff',
suffixOffset = 0,
className, className,
tooltip, tooltip,
...restProps ...restProps
} = this.props; } = this.props;
const cls = classNames(styles.ellipsis, className, { const cls = classNames(styles.ellipsis, className, {
[styles.lines]: (lines && !cover), [styles.lines]: (lines && !isSupportLineClamp),
[styles.linesCover]: (lines && cover), [styles.lineClamp]: (lines && isSupportLineClamp),
}); });
if (!lines && !length) { if (!lines && !length) {
...@@ -155,29 +145,30 @@ export default class Ellipsis extends Component { ...@@ -155,29 +145,30 @@ export default class Ellipsis extends Component {
return (<EllipsisText className={cls} length={length} text={children || ''} tooltip={tooltip} {...restProps} />); return (<EllipsisText className={cls} length={length} text={children || ''} tooltip={tooltip} {...restProps} />);
} }
// lines cover const id = `antd-pro-ellipsis-${`${new Date().getTime()}${Math.floor(Math.random() * 100)}`}`;
if (cover) {
const id = `antd-pro-ellipsis-${`${new Date().getTime()}${Math.floor(Math.random() * 100)}`}`; // support document.body.style.webkitLineClamp
const style = `#${id}:before{background-color:${suffixColor};padding-left:${suffixOffset}px;}`; if (isSupportLineClamp) {
const style = `#${id}{-webkit-line-clamp:${lines};}`;
return ( return (
<div <div id={id} className={cls} {...restProps}>
{...restProps}
id={id}
ref={this.handleRef}
className={cls}
style={{
...restProps.style,
maxHeight: `${lines * lineHeight}px`,
}}
>
<style>{style}</style> <style>{style}</style>
{children} {
</div> tooltip ? (<Tooltip title={text}>{children}</Tooltip>) : children
); }
</div>);
} }
// lines no cover const childNode = (
const suffix = tooltip ? <Tooltip title={text}>...</Tooltip> : '...'; <span>
{
(targetCount > 0) && text.substring(0, targetCount)
}
{
(targetCount > 0) && (targetCount < text.length) && '...'
}
</span>
);
return ( return (
<div <div
...@@ -186,10 +177,9 @@ export default class Ellipsis extends Component { ...@@ -186,10 +177,9 @@ export default class Ellipsis extends Component {
className={cls} className={cls}
> >
{ {
(targetCount > 0) && text.substring(0, targetCount) tooltip ? (
} <Tooltip title={text}>{childNode}</Tooltip>
{ ) : childNode
(targetCount > 0) && (targetCount < text.length) && suffix
} }
<div className={styles.shadow} ref={this.handleShadowChildren}>{children}</div> <div className={styles.shadow} ref={this.handleShadowChildren}>{children}</div>
<div className={styles.shadow} ref={this.handleShadow}><span>{text}</span></div> <div className={styles.shadow} ref={this.handleShadow}><span>{text}</span></div>
......
.textOverflowMulti(@line: 3, @bg: #fff) {
overflow: hidden;
position: relative;
line-height: 1.5em;
max-height: @line * 1.5em;
text-align: justify;
margin-right: -1em;
padding-right: 1em;
&:before {
background: @bg;
box-shadow: 2px 0 2px 1px rgba(255, 255, 255, 0.2);
content: '...';
padding-left: 0;
position: absolute;
right: 14px;
bottom: 0;
}
&:after {
background: white;
content: '';
margin-top: 0.2em;
position: absolute;
right: 14px;
width: 1em;
height: 1em;
}
}
.ellipsis { .ellipsis {
display: inline-block; display: inline-block;
word-break: break-all; word-break: break-all;
...@@ -45,7 +17,10 @@ ...@@ -45,7 +17,10 @@
} }
} }
.linesCover { .lineClamp {
.textOverflowMulti(); position: relative;
display: block; overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
} }
...@@ -13,9 +13,6 @@ order: 10 ...@@ -13,9 +13,6 @@ order: 10
参数 | 说明 | 类型 | 默认值 参数 | 说明 | 类型 | 默认值
----|------|-----|------ ----|------|-----|------
tooltip | 移动到 `...` 展示完整内容的提示,在长度截取和覆盖模式的行数截取下可用 | boolean | - tooltip | 移动到文本展示完整内容的提示 | boolean | -
length | 在按照长度截取下的文本最大字符数,超过则截取省略 | number | - length | 在按照长度截取下的文本最大字符数,超过则截取省略 | number | -
lines | 在按照行数截取下最大的行数,超过则截取省略 | number | `1` lines | 在按照行数截取下最大的行数,超过则截取省略 | number | `1`
cover | 在按照行数截取下开启覆盖模式,这种模式 `...` 是使用样式覆盖到文本上的,所以文本内容可以是 `ReactNode` | boolean | false
suffixColor | 在覆盖模式下后缀符号 `...` 的背景颜色 | string | `#fff`
suffixOffset | 在覆盖下后缀符号 `...` 位置偏移量,用于更精细的调整截取位置 | number | `0`
...@@ -68,7 +68,7 @@ export default class CardList extends PureComponent { ...@@ -68,7 +68,7 @@ export default class CardList extends PureComponent {
avatar={<img alt="" className={styles.cardAvatar} src={item.avatar} />} avatar={<img alt="" className={styles.cardAvatar} src={item.avatar} />}
title={<a href="#">{item.title}</a>} title={<a href="#">{item.title}</a>}
description={( description={(
<Ellipsis lines={3} cover suffixOffset={2}>{item.description}</Ellipsis> <Ellipsis className={styles.item} lines={3}>{item.description}</Ellipsis>
)} )}
/> />
</Card> </Card>
......
...@@ -22,6 +22,9 @@ ...@@ -22,6 +22,9 @@
} }
} }
} }
.item {
height: 64px;
}
} }
.extraImg { .extraImg {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment