实现文本超行缩小字号

953 阅读2分钟

之前在工作和面试中都遇到这个问题,就是文字太多的时候,文本超行,所以产品希望就是当文字超出一行的时候缩小字号,缩小完要是还是超出一行,再缩小,直到文字大小低于多少字号(最小字号值可配)则省略号显示。 我们来思考一下两个问题?

  • 1. 怎么判断文本是否超行?
  • 2. 怎么一直监听dom的fontSize属性?

怎么判断文本是否超行?

当文本超行的时候,我可以通过设置 overflow-x: auto css属性,给它横向滚动条,然后这个时候可以通过 scrollWidth 属性获取文本的宽度,再通过 offsetWidth 属性获取内容区的实际宽度,两者进行对比即可知道是否超行。对属性不理解的可以看下图加深理解

image.png

怎么监听dom属性的变化?

Mutation Observer 可以监测到 DOM 元素上任何属性的变化,简单了解一下Mutation Observer

Mutation Observer(变动观察器)是监视DOM变动的接口。DOM发生任何变动,Mutation Observer会得到通知。

方法

disconnect() 阻止 MutationObserver 实例继续接收的通知,直到再次调用其 observe() 方法,该观察者对象包含的回调函数都不会再被调用。

observe() 配置 MutationObserver 在 DOM 更改匹配给定选项时,通过其回调函数开始接收通知。

takeRecords() 从 MutationObserver 的通知队列中删除所有待处理的通知,并将它们返回到 MutationRecord 对象的新 Array 中。

实践

结合前面的两个问题的解决方案我们来实践一下

首先我们先看一下前置条件,一般需要这么处理的是 单行文本固定宽,还需要一个超出隐藏的类,方便后续配置,所以需要用到css属性如下

font-size
width
overflow-x: auto; 
white-space: nowrap; // 文本不换行

// 超出隐藏
.ellipsis {
    .overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

js逻辑如下

  // css
  .ellipsis {
    .overflow: hidden; //超出的文本隐藏
    text-overflow: ellipsis; //用省略号显示
    white-space: nowrap; //不换行
  }
  // html
  <div id="textNode">这是一个很长很长很长很长很长很长很长很长很长很长很长很长的文本</div>

  // js
  const element = document.getElementById('textNode')
  const minFontSize = '12' // 需要设置的最小字体大小
  const callback = () => {
    const scrollWidth = element.scrollWidth // 文本长度
    const offsetWidth = element.offsetWidth // 固定宽度
    if (scrollWidth > offsetWidth) {
      const fontSize = element.style.fontSize.replace('px', '')
      if (fontSize - 2 < minFontSize * 1) {
        element.classList.add('ellipsis') // 超出隐藏
        mo.disconnect() // 取消监听
      } else {
        element.style.fontSize = `${fontSize - 2}px`
      }
    }
  }
  const mo = new MutationObserver(callback)
  const options = {
    attributes: true // 监听dom属性变化
  }
  mo.observe(element, options)