实现 textarea 自适应高度最佳实践。

3,637 阅读5分钟

最近有点空闲时间又在捣鼓一些东西,就比如说这次碰到的一个小问题是,在输入文本的时候一开始想到的是用 input 标签,但是这个标签只能支持一行,如果超出的情况下就会隐藏到后面看不见,这会导致不好使用体验。而且这次要做的也是多文本输入,抛弃 input 使用改成多文本可以换行的 textarea 实现,但是多文本也有自己的问题,虽说可以自己设置默认高度,然后超出会出滚动条,这样的就跟之前的一样也是隐藏出去的,那么需求有了,怎么去实现即不超出又能自动换行的 textarea 呢?

貌似,上面的需求很普遍,在以往的过程中都不会考虑这个问题,只要设置高一点的高度,加上设置 css 属性的 resize-y 使其纵向拉伸,这样就能解决一点问题,现在不去说这个我们可以换一个角度说怎么实现自适应高度的问题。

抛出这个问题,我想大部分人肯定想到会是用 js 实现一把梭哈 😂 ,不说不行,但也是最不优雅的一种,且不说实现起来复杂多变,还要计算个文字的大小行高等等,麻烦的一比。所以这种方式忽略考虑。

第二个,可以用 h5 的属性 contenteditable="true" 来实现,此属性加入到 div 中可以让其可以编辑,差不多就相当于一个 textare 的使用,而且用起来方便操作简单,但问题是使用回车之后里面的文字内容做成div 包裹起来,使其获取内容元素不是很方便,所以可以考虑。

第三个,可以使用 css 的方式实现,思路其实也很简单,就是用一个 span 的高度去顶替 textarea 的高度,什么意思呢。打字也说不明白,看图就行了。 微信截图_20221022201448.png 如上面的图所示,想象一下绿色的块是最大的盒子,然后里面包裹着两个盒子,一个黑色的 span 盒子和一个红色的 textarea 盒子,为什么会挤在一起,是因为我把红色的 textarea 的盒子设置成了绝对定位的布局方式 absolute,而父元素的绿色盒子设置成相对定位 relative,然后再把红色盒子的宽高都设置其父元素的 100%,也就是跟父元素一样的宽高大小了,最后我们再设置关键的 span 元素,为什么说是这个是关键,因为它需要的高度需要自己撑开给父元素,怎么撑开,那就要在 span 里面加入内容了,可以是 \n 的回车也可以是纯文字的内容,只要文字多起来 span 的高度就是撑高,顺带的父元素也会变高,那必须的红色盒子的 textarea 也会跟着父元素的 100% 变化!

surprise, 是不是完美。

废话太多,还不如直接上代码演示;

html部分 🍎

<div>
  <span></span>
  <textarea></textarea>
</div>

css部分 🍇

div {
  position: relative;
  width: 100px;
  border: 1px solid red;
}
span {
  display: block;
  min-height: 24px;
  white-space: pre-wrap;
  word-wrap: break-word;
  visibility: hidden; /* 一定不要少了给它隐藏哦,留个站位 */
}
textarea {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  line-height: 24px;
  resize: none;
  outline: none;
  border: none;
  overflow: hidden;
  margin: 0;
  padding: 0;
}

JS 部分

const area = document.querySelector('textarea')
const text = document.querySelector('span')
area.addEventListener('input', function(event) {
  text.innerHTML = event.target.value;
})

很简单的代码,试运行一下吧,怎么感觉有点和自己想的出路比较大的,回车的时候没有及时增高,会出现一闪的效果,仔细观察一下,当我不输入任何文字的时候直接回车,就会出现一小段的换行,按下第二次回车的时候才出现了正常的换行,这是为什么? 按 f12 对比一下 dom 数据的变化,可以发现,第一次的回车显然是没有效果的,因为 span 的内容里面是没有加入回车符的,直到第二次才有效果,在尝试加入一个文字就可以正常走流程了,但是最后一行回车的时候还是会有闪屏的问题出现,在中间回车就不会,思考是不是中间缺少神东西导致换行失效?实话说我没找到为什么的原因,但是尝试给后面加一个空格符之后,后面的闪动就消失了!!

修改一下 js 代码

text.innerHTML = event.target.value + ' ';

后面加入一个空的字符,就很流畅的回车了。但,凡是都还有但是,细心的朋友肯定又发现了,一直回车下去的话,文字就会向上偏移一点,这也是换行符导致的,既然每次添加的时候后面都加了空格符,那么在第一次的时候也要记得加上去才行哦。

再次修改一下 html 代码

<div>
  <span> </span> // 加入一个空格符
  <textarea></textarea>
</div>

这次改完之后,在运行全部的代码,完美自适应!接下来就只要获取文本的内容就可以了,也不需要用 JavaScript 计算什么行高了。很多问题都可以优先考虑使用 css 尝试一下是不是可这样解决,不要复杂化,记录一下。

happy end