关于文本溢出的奇怪需求——中间溢出
例:我是文本我很长我溢出了......但我的溢出省略号要放中间。
思路
- 确定文本框宽度、字体大小,通过文本长度和字体大小计算出文本单行总长度。
- 比较文本单行总长度与文本框宽度大小
- 文本单行总长度<=文本框宽度时,直接展示文本。
- 文本单行总长度>文本框宽度时, 获取展示行中间文本的下标作为省略号前文本,根据展示行中间文本的下标及文本总长度截取文本末尾部分作为省略号后文本,三者拼接实现中间省略的效果。
图解
- index = Math.floor(width/fontSize)/2;
- const textStart = truncatedText.slice(0, index-1);
- const textEnd = truncatedText.substring(text.length - 1, text.length - index);
效果
组件代码
- 定义入参:
-
text:文本内容
-
width:行宽
-
fontSize:字体大小
-
type:省略号的位置
-
customerStyle:自定义样式
-
- 代码
import { Tooltip } from 'antd';
export const ellipsisText = ({
text,
width,
fontSize,
type='middle',
customerStyle,
}: {
text: string,
width: number,
fontSize: number,
customerStyle?: any, // 自定义样式
type?: 'start'|'middle'|'end', // 省略号类型
}) => {
const containerRef = useRef(null);
useEffect(() => {
const container = containerRef.current;
const textContainer = container.querySelector('.text-container');
switch(type) {
case 'end':
return
case 'middle':
// 比较:总宽度(文本长度x字体大小)和demo宽度的大小
const totalWidth = text?.length*fontSize
if (totalWidth > width) {
// 获取中间文本下标
const index = Math.floor(width/fontSize)/2;
const truncatedText = textContainer.innerText;
// 截取第一个字到省略号前文本
const textStart = truncatedText.slice(0, index-1);
// 截取最后一个字到省略号后文本
const textEnd = truncatedText.substring(text.length - 1, text.length - index);
containerRef.current.innerText = `${textStart}...${textEnd}`;
} else {
containerRef.current.innerText = text
}
return
case 'start':
return
}
}, []);
function styleText() {
switch(type) {
case 'end':
return {
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
};
case 'middle':
return {}
case 'start':
return {
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
direction: 'rtl',
}
}
};
const containerStyle = {
fontSize,
width: `${width}px`,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
overflow: 'hidden',
...customerStyle,
} as any;
const elliType: any = styleText();
return (
<Tooltip placement="top" title={text}>
<div style={containerStyle} ref={containerRef}>
<span className="text-container" style={{ ...elliType }}>{text}</span>
</div>
</Tooltip>
);
};
-
使用
import React from 'react'
export default function ell() {
return (
<div>
{ellipsisText({
text: '我们据此也能推断出,眼下的司马睿集团在军事上只能仰仗王敦。王敦并没有独吞战果,他上表司马睿,申请任命周访为豫章太守。周访之前因为江州战役的功劳升寻阳太守,驻扎今江西九江一带。而南昌所在的豫章才是江州枢纽所在,也是江州刺史办公场所。从寻阳太守到豫章太守,是明显的升职。王敦上表的时机还有些微妙。此前湘州战役尚在进行中,司马睿就曾升周访为龙骧将军。如今局势已定,司马睿大概率会再度封赏周访。王敦抢先为周访表功求官,明显是想加以拉拢。周访忠诚、善谋,有大局观,又行事果断。在整个江东,除陶侃以外,就属他最能战善战。在后续的荆州平叛中,王敦还要借助他的力量。司马睿也同样要争取周访的忠诚,于是在应王敦之请升周访为豫章太守后,额外加封“征讨都督,赐爵寻阳县侯”,也就是有对外征讨大权,同时封县侯。',
fontSize: 12,
width: 300,
customerStyle: { padding: 4, border: '1px solid', color: '#f50' },
})}
</div>
)
}
效果展示
- 入参1:fontSize: 16, width: 200
- 入参1:fontSize: 12, width: 200
- 入参3:fontSize: 12, width: 200,type='start', customerStyle: { color: '#f50', border: '1px solid #f50', padding: 4 } -