多行文本超出,中间显示省略号的终极方法(适配多语言)

嘿,各位前端圈的兄弟姐妹们!今天我们来聊一个让无数英雄豪杰折腰的"史诗级"难题:文本溢出处理

你肯定见过它,也肯定被它折磨过。产品经理悠悠地走过来,指着屏幕说:"这个标题太长了,末尾显示三个点太丑了,能不能在中间显示省略号?像 前端开发...从入门到放弃 这样,前后都给我留点内容,让用户知道大概是个啥。"

你一听,心里咯噔一下。CSS 的 text-overflow: ellipsis; 就是个"偏科生",它只会末尾截断,让它中间干活,它直接"躺平"。

特别是当你的应用需要支持多语言,比如中文、日文、阿拉伯文......这些语言的字符宽度千差万别,用固定的字符数去截断,简直是"盲人摸象",效果惨不忍睹。

难道我们就束手无策了吗?别急,今天,我就掏出我的压箱底宝贝,一个能精准打击、完美适配多语言的"终极解决方案"!

传统方案的"阿喀琉斯之踵"

在亮出大招之前,我们先来"鞭尸"一下传统方案,看看它们为什么不行。

  1. 纯 CSS 方案text-overflow: ellipsis; 只能单行、末尾截断。想多行?想中间?对不起,请出门左转,找 line-clamp 商量去,但它也只能在末尾截断。
  2. JS 字符截断str.slice(0, 10) + '...' + str.slice(-10)。这种"一刀切"的方式,在等宽字体下或许能看,但在现代浏览器各种花里胡哨的字体面前,简直就是一场灾难。一个 W 的宽度可能顶三个 i,你按字符数切,切出来的宽度能一样吗?

所以,我们需要一个能精确测量文本宽度 的方案。这时候,一位沉睡的巨人被我们唤醒了------Canvas API

终极武器:Canvas 的"火眼金睛"

你没看错,就是那个平时用来画图、做游戏的 Canvas。它有一个隐藏技能:ctx.measureText(text)。这个方法能像一把精确的游标卡尺,量出任意一段文本在指定字体下的真实像素宽度!

有了这把"神兵利器",我们就可以制定一个完美的"截断策略"了。

核心思路:

  1. 先用"游标卡尺"量一下完整文本的宽度,如果比容器窄,那啥也别干,完美显示。
  2. 如果宽了,我们就启动"双指针"算法。想象一下,你的左手和右手分别从文本的开头和结尾,同时向中间"吃"字符。
  3. 每吃一口,就把左右手里的文本,加上中间的省略号 ...,组合起来,再用"游标卡尺"量一下。
  4. 如果发现组合后的宽度第一次超过了容器的宽度,就说明"吃多了"。赶紧把刚才多吃的那个字符吐出来,然后收工!
  5. 最后把"左手里的文本 + 省略号 + 右手里的文本"拼在一起,大功告成!

听着是不是有点像"两只小蜜蜂呀,飞在花丛中"?

别急,我们上代码,一看就懂!

代码实战:庖丁解牛

这是我们的核心方法

javascript 复制代码
/**
 * 获取中间省略的文本
 * @param {string} text - 原始文本
 * @param {number} maxWidth - 容器的最大宽度
 * @param {string} font - 字体样式 (e.g., '16px Arial')
 * @returns {string} 处理后的文本
 */
getMiddleEllipsisText(text, maxWidth, font) {
  const ellipsis = '...';
  
  // 1. 准备我们的"测量工具"------Canvas
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  
  // 2. 设置"游标卡尺"的量程。关键!必须使用真实的字体样式!
  ctx.font = font || '16px Arial';

  // 3. 先量一下全文,如果放得下,直接返回,别折腾了。
  if (ctx.measureText(text).width <= maxWidth) return text;

  // 4. 准备"左右开弓"的指针
  let left = 0, right = text.length - 1;
  let leftStr = '', rightStr = '';

  // 提前量好省略号的宽度,免得循环里重复计算
  const ellipsisWidth = ctx.measureText(ellipsis).width;

  // 5. 开始"向中心靠拢"的循环
  while (left < right) {
    // 左手"吃"一个字符
    leftStr += text[left];
    // 右手"吃"一个字符
    rightStr = text[right] + rightStr;
    
    // 拼接起来,看看有多宽
    const combined = leftStr + ellipsis + rightStr;
    
    // 6. 关键判断:如果超宽了!
    if (ctx.measureText(combined).width > maxWidth) {
      // 说明刚才"吃"多了,把最后那个字符"吐"出来
      leftStr = leftStr.slice(0, -1);
      rightStr = rightStr.slice(1);
      break; // 赶紧跳出循环,再吃就撑爆了!
    }
    
    // 如果没超宽,继续向中心移动
    left++;
    right--;
  }
  
  // 7. 返回最终成果
  return leftStr + ellipsis + rightStr;
},

这段代码的逻辑是不是清晰又有趣?就像两个贪吃蛇,从两头往中间吃,吃到快撑破肚皮的那一刻就停下来。

如何优雅地使用它?

光有核心方法还不够,我们得知道在真实项目中怎么调用。下面是一个典型的 Vue 使用场景:

javascript 复制代码
// 假设这是你的 Vue 组件的一个方法
updateVideoTitle() {
  // 1. 找到要操作的 DOM 元素
  const videoTitleRef = this.$refs.videoTitleRef;
  if (!videoTitleRef) return; // 元素不存在,溜了溜了

  // 2. 清空一下,防止重复调用时内容叠加
  videoTitleRef.innerHTML = '';
  
  // 3. 【多语言适配的关键!】获取元素真实的、计算后的字体样式
  //    这一步确保了我们测量的宽度和实际渲染的宽度完全一致!
  let font = window.getComputedStyle(videoTitleRef).font;
  
  // 4. 获取原始文本和容器的最大宽度
  let text = this.item.name;
  let maxWidth = videoTitleRef.offsetWidth;
  
  // 5. 调用我们的"屠龙术",获取处理后的文本
  videoTitleRef.innerText = this.getMiddleEllipsisText(text, maxWidth, font);
}

划重点window.getComputedStyle(videoTitleRef).font 是整个方案能够完美适配多语言 的灵魂!它会把元素上所有 CSS 关于字体的属性(font-size, font-family, font-weight 等)都给你抓过来,保证我们的 Canvas 测量环境和真实渲染环境分毫不差。无论是中文的"微软雅黑",还是日文的"ヒラギノ角ゴ",都能被精准拿捏!

总结一下,这个"终极方法"好在哪?

  1. 精准控制:基于像素级测量,不是字符数,结果完美。
  2. 中间省略:完美实现产品经理的"刁钻"需求。
  3. 多语言友好 :配合 getComputedStyle,无视任何语言的字符宽度差异。
  4. 兼容性好:Canvas API 的兼容性,比你想象的要好得多。

当然,它也有一个小小的"缺点":它需要 JavaScript 计算。对于海量列表(比如几千条),在 resize 事件中频繁调用可能会有性能开销。但大多数场景下,比如处理标题、卡片名称等,这点开销完全可以忽略不计。

所以,下次再遇到文本溢出的难题,别再对着 CSS 叹气了。请出我们这位 Canvas 大神,用代码的智慧,优雅地解决问题吧!

好了,今天的"屠龙秘籍"就分享到这里。觉得有用的话,别忘了点赞收藏,顺便分享给你身边那个正在为文本溢出抓狂的兄弟!我们下期再见!😎

相关推荐
宇余11 分钟前
从 useState 到 URLState:前端状态管理的另一种思路
前端·vue.js
白兰地空瓶17 分钟前
🚀 10 分钟吃透 CSS position 定位!从底层原理到避坑实战,搞定所有布局难题
前端·css
T___T28 分钟前
Ajax 数据请求详解与实战
javascript·面试
onthewaying36 分钟前
在Android平台上使用Three.js优雅的加载3D模型
android·前端·three.js
冴羽43 分钟前
能让 GitHub 删除泄露的苹果源码还有 8000 多个相关仓库的 DMCA 是什么?
前端·javascript·react.js
悟能不能悟44 分钟前
jsp怎么拿到url参数
java·前端·javascript
程序猿小蒜1 小时前
基于SpringBoot的企业资产管理系统开发与设计
java·前端·spring boot·后端·spring
Mapmost1 小时前
零代码+三维仿真!实现自然灾害的可视化模拟与精准预警
前端
程序猿_极客1 小时前
JavaScript 的 Web APIs 入门到实战全总结(day7):从数据处理到交互落地的全链路实战(附实战案例代码)
开发语言·前端·javascript·交互·web apis 入门到实战
suzumiyahr1 小时前
用awesome-digital-human-live2d创建属于自己的数字人
前端·人工智能·后端