乐趣区

关于前端:前端正确处理文字溢出的思路

前言: 最近在我的项目中须要做到相似于 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 主动省略文字

退出移动版