前言: 最近在我的项目中须要做到相似于 Mac 下这种,当屏幕宽度足以容下以后文件名称的时候,文件名称全副展现,不做省略。

然而当用户缩放浏览器显示的尺寸时,咱们须要做到省略两头的文字,抉择保留后缀这种计划。如下图所示:

我集体也是感觉这个计划是最好的,因为大部分状况下,用户更关怀的是这个文件的类型,而后缀名的保留往往是最佳的抉择。我集体也查阅了很多相干文章,并且借鉴了一些已有轮子的代码思路,实现了一个合乎咱们我的项目中需要的一个组件。


一.组件成果预览

  1. 单行文字溢出时主动省略,并且不保留后缀。
  2. 单行文字溢出时主动省略,并且保留后缀。
  3. 多行文字溢出时,而后再开始省略。这个状况是咱们我的项目中比拟非凡的场景。简略来说就是假如我当初想让文字显示两行,如果两行的时候没有溢出,那么失常显示。如果两行状况下还是溢出了,那么我再去解决溢出的文字。
    假如这是没有做任何操作的的成果:

    应用咱们的组件当前的成果:

    (tips:不肯定必须是两行,三行,四行都是能够的。咱们接下来实现的组件会让你高度自定义去解决文字溢出的场景。)
  4. 如果你想本人先尝试一下成果,那么你能够疾速应用 npm 装置一下。

    • npm i auto-ellipsis-text
    • pnpm i auto-ellipsis-text
    • yarn add auto-ellipsis-text

    原仓库地址: AutoEllipsisTxt主动省略文字

  5. 应用起来也非常简单,你只须要包裹住你的文字即可

  6. 话回正题,接下来我会一步一步解说我实现这个组件的思路,我写的这个组件不肯定是最优的,你须要做到知其然并知其所以然,而后欠缺我写的组件的不足之处,你能够实现本人的主动省略文本计划,才是本文的目标。

二. 单行溢出的解决

  1. 咱们先只思考单行的状况。通常咱们在本人的利用中展现很多文件信息的时候,往往抉择的布局形式就是高度是肯定的,说白了就是高度其实咱们是定死的,宽度咱们不确定,因为用户有可能会在某些状况下拖动浏览器,造成宽度发生变化,然而总会给宽度一个最小值和一个最大值来保障排版的统一性。
  2. 款式方面,在这里我应用的是 UnoCSS ,将款式內联在了标签里,如果你还不理解这种写法,你能够点击下方的文章学习。不过即便你之前从未理解过 UnoCSS ,也不会影响你上面的浏览,因为款式不是本文的重点,并不影响整体浏览。
    手把手教你如何创立一个代码仓库
  3. 让咱们先发明一个简略的溢出场景,代码很简略,容器是一个 width 最大值为 200pxheight 为固定 30pxdiv

    当初页面上的成果如下图:
  4. 能够很清晰的看出,因为咱们文字在容器内放不下,然而咱们又没对溢出这一非凡场景做出解决,所以就造成了以后页面的成果。先别急,咱们一步一步来。
  5. 最开始我去查阅 MDN 的时候,查阅到了一个 “确认过眼神,你就是我要找到人” 的属性。
  6. 什么?text-overflow,咱们要找到不就是文字溢出时候的解决吗?我兴奋的赶快增加到了我的组件上。

    成果如下:

    而后看着毫无变动的页面,开始狐疑我本人是不是单词拼错了,而后一个字母字母的比对,排除了单词打错字的状况,但页面还是没有变动。
  7. 于是我又返回 MDN 去查看本人是否脱漏了哪些货色,发现了这样一段文字。

    这里间接说论断,其实 text-overflow 这个属性不会为了让文字省略而去发明省略的场景。它其实是在你解决过溢出场景之后,帮你做对于文字溢出的的二次非凡解决。当你对于页面溢出做没有任何操作时,这个属性其实是有效的。 (留神:它仅仅只解决文字溢出的场景。)
  8. 既然你说了,让咱们增加额定的属性:overflow-hiddenwhite-space,那么咱们就本人增加。咱们先只增加一个 overflow-hidden 来看看会产生什么。

    咱们发现,上面多进来的文字倒是被省略了,然而咱们的省略号呢??我就不卖官子了,其实造成这个的起因的答案就是上面这句话:
  9. 咱们认真看下面咱们溢出的场景。

    咱们上面两行文字其实是溢出在了盒子下方,正好对应了下面 text-overflow 的介绍,“无奈在盒子上面溢出” 这句话。
  10. 在这里咱们就须要制作一个让文字强制不换行的场景。那么就须要用到咱们另外一个非常重要的属性,white-space

    咱们本节只须要关系 nowrap 这一个值即可。剩下的值如果读者有趣味能够自行理解,咱们不过多解释。
  11. 首先你要晓得,其实咱们 web 页面的换行,并不是毫无意义的本人就换行了,而是都有一个暗藏的换行符,你能够把这个暗藏的换行符浅浅的了解为 white-space(空格)
  12. 了解了下面那段话,那咱们的属性 white-space:nowrap 的中文含意就非常显著了。white-space对应空格no-wrap 代表不换行。连起来的意思就是,遇到空格不换行。而咱们的换行其实有一个暗藏的 white-space ,那么咱们增加这个属性当前,就会造成一个不会换行的场景。
  13. 让咱们先把 text-ellipsisoverflow-hidden 属性删除,只增加 white-space:nowrap 看看页面成果会是怎么样。

    成果如下:

    能够看到,咱们省略了那个暗藏的换行符,所以文字不会主动换行了,那么整段文字都显示到了一行上。此时咱们再加上咱们的两个属性,overflow-hiddentext-ellipsis,神奇的一幕就产生了。

    咱们仅仅只应用了几个 CSS 属性就实现了单行状况下不保留后缀的文字溢出解决。

三. 后期筹备

  1. 首先你须要筹备一个 autoEllipsis.vue 文件,首先写出上面的代码,来和我一起实现这个组件。

    <template>  <div id="autoEllipsisWrapper" ref="container" v-bind="$attrs"><span ref="text">  <slot /></span>  </div></template>
  2. 请留神这个 id 叫做 containerdiv 元素将在接下来的内容中起到至关重要的作用。
  3. 接下来应用 ref 别离去拿到这两个 dom 元素。
  4. 最初咱们须要设计一个函数,在组件挂载当前,让它去正确处理咱们文字溢出的场景。
  5. 接下来的需要就是,这个 autoEllipsis 函数如何去实现。别着急写代码,我晓得你当初有可能还是一头雾水无从下手,让我先带你理清思路而后再开始写代码。

四. 理清思路

  1. 首先咱们因为要做到通用性所以, container 的宽度是不能确定的,它的宽度须要依据它外层的父元素来决定,也就是上文中咱们提到的有一个最大值最小值宽度的元素。

    换句话说,咱们这个 container 要去动静的拿到外层父元素的宽度。
  2. 咱们先不讲代码如何实现,咱们假如当初咱们曾经拿到了,就叫做 fatherWidth。而后咱们再通过刚刚的 ref 获取到的 text dom 元素去拿到里面传进来的文字内容。通过拿到这个 span 元素的 offsetWidth ,就能够拿到文字的长度。通过判断文字的 offsetWidth 是否大于 fatherWidth 。而后咱们通过两个宽度相减,能够得出咱们到底溢出的文字宽度为多少。
  3. 拿到溢出的宽度当前,那么咱们就能够用溢出宽度来除以文字大小,(overWidth/fontSize) ,就能够算出咱们到底溢出了多少文字。
  4. 假如当初咱们当初溢出宽度为 200px。咱们的文字大小为 20px,那么 200/20 就算出咱们当初溢出了 10 个字。
  5. 咱们并且一开始就拿到了总的文字内容,如果咱们之前的文字总数为 30 个。那么在这个状况下咱们屏幕上只展现了 20 个文字,因为有 10 个字溢出被咱们疏忽了。
  6. 到这里之后,咱们要做的事件就非常简单了,咱们只须要从原来 30 个字的两头开始做切割。一边去掉 5 个,那么此时容器恰好能够容下 20 个字。两头咱们再手动加上 “...” 省略号不就完满达成了吗?
  7. 下面想表白的意思用大白话来讲,其实也就是去掉两头的10个文字,而后轻易再找一个字替换成字符串三个点 ...

五. 实现 autoEllipsis 函数

  1. 第一步就是为了拿到咱们放入的文字宽度。正文曾经写的很分明了,就不过多赘述。
  2. 而后咱们再去拿里面父元素的宽度。此时会呈现第一个分支, container 的宽度小于父元素的宽度,很容易能够猜到当初咱们的文字内容是齐全能够包容的,不须要做非凡解决。
  3. 第二个分支,当咱们的 container 宽度大于了父亲元素的宽度,那么咱们能够通过传递 props 来辨别是否须要保留后缀,如果不须要保留后缀,咱们间接给 container设置咱们第二个题目解说的常识就OK了。

六. 保留后缀的实现

  1. 如果看到这里,你还没有正确的保留后缀思路,我倡议你从新去观看一下题目四,这里咱们大抵的思路就是为了拿到父元素能够包容多少文字。
  2. 这里咱们的思路其实就是计算出得出咱们须要删除多少个文字
  3. 很简略的思路,就是字符串应用 slice 切割咱们下面计算得出的,两边须要删除多少文字。
  4. 最初的要害一步,咱们须要把 containerwhite-space 属性设置为 normal,因为咱们曾经正确的解决了文字数量,当初的 container 曾经不会溢出了。

七. 源码

上面是本组件的外围代码 autoEllipsis 函数的源码

function autoEllipsis(container: HTMLElement, textNode: HTMLSpanElement) {  const str = premitiveText; //1.拿到的所有文字信息  textNode.textContent = str; //2.将所有文字放入到咱们的 span 标签中  container.style.whiteSpace = "nowrap"; //3.先将文字全副放入到《一行》中,为了计算整体宽度  container.style.width = "fit-content"; //4. 给 container 设置 fit-content 属性,就能够拿到正确的内容宽度  const containerWidth = container.clientWidth; //5. 拿到了 container 的宽度  const parent = container.parentElement; // 拿到内部父元素的宽度  const parentWidth = parent!.clientWidth || parent!.offsetWidth;  if (containerWidth <= parentWidth) {    //如果container 的宽度《小于》父元素的宽度,不做任何解决    textNode.textContent = str;    return;  } else if (cssEntirely.value) {    container.style.width = parentWidth + "px";    container.style.whiteSpace = "nowrap";    container.style.textOverflow = "ellipsis";    container.style.overflow = "hidden";    return;  } else {    const textWidth = textNode.offsetWidth; //1. 拿到文字节点的宽度    const strNumer = str.length; //2. 拿到文字的数量    const avgStrWidth = textWidth / strNumer; //3. 拿到均匀每个文字多少宽度    const canFitStrNumber = Math.floor(      (parentWidth * props.startEllipsisLine) / avgStrWidth //4. 依据父元素的宽度来计算出能够包容多少文字    );    const shouldDelNumber = strNumer - canFitStrNumber + 1.5; //1. 算出须要删除几个文字(1.5是为了省略号的宽度    const delEachSide = shouldDelNumber / 2; //2. 因为要保留两头,所以咱们不能只从结尾删除,也须要从中间删除    const endLeft = Math.floor(strNumer / 2 - delEachSide); //3. 因为上面要用到 slice 所以须要计算出 index    const startRight = Math.ceil(strNumer / 2 + delEachSide); //4. 和下面同理    switch (props.suffix) {      case true: {        textNode.textContent =          str.slice(0, endLeft) + "..." + str.slice(startRight);        break;      }      case false: {        textNode.textContent = str.slice(0, -shouldDelNumber) + "...";        break;      }    }    container.style.wordBreak = "break-all";    container.style.whiteSpace = "normal";  }}

八. 优化点

这个组件目前在 ... 省略号的文字占用上,并不能精确的依据文字大小调整所需的字数。也就是上面的 1.5 这个数字无奈准确的算出,然而目前咱们我的项目的文字大小是确定的,所以我也就没有再优化了,还心愿各位能够提交 Pr 来一起欠缺这个组件。

原仓库地址: AutoEllipsisTxt主动省略文字