修复提示框文字换行问题

This commit is contained in:
2025-04-26 18:43:22 +08:00
parent 6c40c4d074
commit 9a22e9092f
5 changed files with 129 additions and 91 deletions
+54 -7
View File
@@ -73,8 +73,14 @@ export function Toast({
// 计算消息行数(用于可能的额外样式调整)
useEffect(() => {
if (message) {
// 简单估算行数: 假设每行平均40个字符,+1确保有足够空间
const estimatedLines = Math.ceil(message.length / 40) + 1;
// 更好地估算中文文本行数:假设每行平均25个中文字符(或50个英文字符)
const estimatedChars = message.split('').reduce((count, char) => {
// 判断是否为中文字符(粗略判断)
const isChinese = /[\u4e00-\u9fa5]/.test(char);
return count + (isChinese ? 2 : 1); // 中文字符算2个宽度单位
}, 0);
const estimatedLines = Math.ceil(estimatedChars / 50);
setMessageLines(Math.max(1, Math.min(estimatedLines, 10))); // 最小1行,最大10行
}
}, [message]);
@@ -91,15 +97,20 @@ export function Toast({
// 自动关闭
useEffect(() => {
if (isOpen && autoClose && !isHovered) {
// 根据消息长度调整显示时间,长消息显示更长时间
// 根据消息长度调整显示时间,长消息显示更长时间
const messageLength = message.length;
const baseDelay = autoCloseDelay || DEFAULT_AUTO_CLOSE_DELAY;
// 按照文本长度比例延长显示时间
const adjustedDelay = Math.min(
autoCloseDelay + (message.length > 100 ? 2000 : 0),
10000 // 最长不超过10
baseDelay + (messageLength > 20 ? messageLength * 30 : 0),
15000 // 最长不超过15
);
const timer = setTimeout(() => {
handleClose();
}, adjustedDelay);
return () => clearTimeout(timer);
}
}, [isOpen, autoClose, autoCloseDelay, handleClose, message, isHovered]);
@@ -139,6 +150,42 @@ export function Toast({
}
}, [handleClose]);
// 处理长文本
const formatMessage = (text: string) => {
// 清理文本中的多余空白,但保留换行符
const cleanedText = text.replace(/[ \t]+/g, ' ');
// 处理中文文本最后两个字符换行问题
const fixChineseWrapping = (content: string) => {
// 如果内容长度小于3,或已有换行符,直接返回
if (content.length < 3 || content.includes('\n')) {
return content;
}
// 检测是否是中文文本
const isChinese = /[\u4e00-\u9fa5]/.test(content);
if (!isChinese) {
return content;
}
// 在中文文本中,添加零宽空格避免最后两个字符换行
// 在文本末尾前两个字符之间添加零宽不换行空格,防止它们被分开
return content.slice(0, -2) + '\u2060' + content.slice(-2);
};
// 如果文本包含换行符,按换行符分割
if (cleanedText.includes('\n')) {
return cleanedText.split('\n').map((line, index) => (
<div key={index} className="toast-message-line">
{fixChineseWrapping(line)}
</div>
));
}
// 如果没有换行符,直接返回整个文本,应用修复
return fixChineseWrapping(cleanedText);
};
// 如果通知未打开,不渲染
if (!isOpen || !portalElement) {
return null;
@@ -147,7 +194,7 @@ export function Toast({
// 使用 Portal 渲染通知
return createPortal(
<div
className={`toast toast-${type} ${isClosing ? 'closing' : ''} ${className} ${messageLines > 3 ? 'toast-multiline' : ''}`}
className={`toast toast-${type} ${isClosing ? 'closing' : ''} ${className} ${messageLines > 1 ? 'toast-multiline' : ''}`}
role="status"
aria-live="polite"
onMouseEnter={handleMouseEnter}
@@ -158,7 +205,7 @@ export function Toast({
{renderIcon()}
</div>
<div className="toast-message">
{message}
{formatMessage(message)}
</div>
</div>
<button