容器内有多个元素时,如何设置超出显示省略号

165 阅读3分钟

先列出两个通用情况,当希望文本内容超出显示省略号时,可采取如下两种方式

一、单行文本

image-20241008172422720.png

HTML 布局

<div class="overflow-text">
  这是一行需要设置超出隐藏的文本内容
</div>

CSS 样式

.overflow-text {
  overflow: hidden; /* 超出隐藏 */
  white-space: nowrap; /* 文本不换行 */
  text-overflow: ellipsis; /* 超出显示省略号 */
}

二、多行文本,在最后一行省略

image-20241008172653312.png

HTML 布局

<div class="overflow-multi">
  这是一段需要设置超出隐藏的文本内容,内容有点长,可能会放不下
</div>

CSS 样式

.overflow-multi {
  overflow: hidden; /* 超出隐藏 */
  word-break: break-all; /* 文本换行 */
  text-overflow: ellipsis; /* 超出显示省略号 */
  display: -webkit-box; /* 可灵活地调整子元素的大小和位置 */
  -webkit-box-orient: vertical; /* 设置子元素的排列方向:vertical =>垂直;*/
  -webkit-line-clamp: 2; /* 超出2行显示省略号 */
}

三、容器内有多个元素时,如何在最后打点

为了方便区分,我把每块小文案设置了不同的颜色,效果图如下:

image.png

先说一下设计思路(可以与下面的图对照着看,会更清晰一些) image-20241008194156988.png

  1. 首先要获取容器(即可视区域)的宽度 wrapWidth

  2. 需要知道容器内能放下几个元素

    2.1 循环遍历子元素,并进行加和,记录实际总宽度 realWidth

    2.2 与容器宽度进行对比

    • 如果 实际总宽度 <= 容器宽度,则记录下来
    • 否则 跳出循环
  3. 计算容器内还剩多少宽度,记为 diff

  4. 为可视区域范围内的下一个元素,限定宽度,设为值 diff,即让它超出显示省略号

    Q:这里为什么不给最后一个元素限定宽度呢?

    A:考虑到有可能是中间任意一个元素宽度超出。

    比如下图,如果第三块橙色区域已经超出容器宽度,此时给最后一个元素限定宽度,是无法达到我们的预期的。

image.png

下面是实现方式

HTML 布局

<div class="overflow-wrap">
  <span>这是一行</span>
  <span>有多个元素</span>
  <span>的文本</span>
  <span>需要超出打点</span>
</div>

Typescript

/**
 * 处理超出隐藏
 * @param dom
 */
const handleOverflow = (dom: HTMLElement) => {
  /** 容器宽度 */
  const wrapWidth = dom.clientWidth
  const children = Array.from(dom.children) as HTMLElement[]
​
  // 获取每个子元素宽度,并记录map
  const childWidthMap: { [key in string]: number } = {}
  children.map((child, index) => {
    const childWidth = child.clientWidth
    childWidthMap[index] = childWidth
  })
​
  // 获取在父元素范围内的元素集合,并保存宽度
  let realWidth = 0
  const realChildWidths: number[] = []
​
  for (const key in childWidthMap) {
    const value = childWidthMap[key]
    const temp = realWidth + value
    /** 元素放不下时 跳出循环  */
    if (temp > wrapWidth) break
​
    realWidth += value
    realChildWidths.push(value)
  }
​
  /** 容器内,除了能放下的元素外,还剩多少宽度 */
  const diff = wrapWidth - realWidth
  const realChildLength = realChildWidths.length// 循环所有元素
  children.map((child, index) => {
    // 当前元素是可视区域内的最后一个,则设置超出隐藏
    if (index === realChildLength) {
      // 设置宽度变量,把宽度代码放在 css 里,可以支持屏幕自适应
      child.style.setProperty("--overflow-width", diff + "px")
      child.classList.add("overflow-item")
    } else if (index > realChildLength) {
      // 当前元素超出可视区域,则直接隐藏
      child.classList.add("overflow-hide")
    }
  })
​
  // 设置超出标识
  if (realChildLength < children.length) {
    dom.classList.add("is-over")
  }
}

CSS 样式

.overflow-wrap {
  display: flex;
  overflow: hidden; /* 超出隐藏 */
  white-space: nowrap; /* 文本不换行 */
}
​
.overflow-hide {
  display: none;
}
​
.overflow-item {
  overflow: hidden; /* 超出隐藏 */
  white-space: nowrap; /* 文本不换行 */
  text-overflow: ellipsis; /* 超出显示省略号 */width: var(--overflow-width); /* 这里的宽度是 js 中为超出元素限定的宽度 */
}

如果更好的方案,欢迎各位大佬指教啦~