最近有点空闲时间又在捣鼓一些东西,就比如说这次碰到的一个小问题是,在输入文本的时候一开始想到的是用 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 尝试一下是不是可这样解决,不要复杂化,记录一下。

最后在线看一下运行效果 地址 ,别忘记改一下里面的代码在运行哦。

- THE END -

自适应 # 58 阅读
分享到:
Like

目录

    评论 (9)

    • 昵称
    • 邮箱
    • 网址
    1. 枫叶枫叶
      枫叶枫叶

      就目前这个文本框的右下角这个小东西,在移动端特别不好用,有美化方案不?十次拖拉九次没效果。

      1. lus
        lus 博主

        可以用我上面文章中的说的方案,如果不考虑回复的文本带标签的就可以用 div 设置 contenteditable 来处理实现自动换行,这就就不需要手动拖拽文本框的高度。

        1. 枫叶
          枫叶

          我是试试看,最近搞兼容给整麻了。怕新特性了。

          1. lus
            lus 博主

            放心大胆的用,不要考虑向下兼容,现在浏览器和手机性能都好的能。

    2. Jdeal
      Jdeal

      感觉用一堆js换一个textarea自适应不太划算,我选择换成div替代,哈哈(๑•̀ㅁ•́ฅ)

    3. 风记星辰
      风记星辰

      直接对textarea的父元素设置 min-height: 24px; 就可以了吧,不太理解为什么要单独元素撑开呢?

      该回复疑似异常,已被系统拦截!
      1. lus
        lus 博主

        这样的话,回车换行过了24的高度就会有滚动条了,不信你可以试试能不能自己撑开。

    4. Sirit
      Sirit

      输入框的大小不是和之前预计要输入的内容的长度提前预留或者根据页面的大小来设置吗?

      你这个评论的输入框有这个效果吗?

      1. lus
        lus 博主

        看上面代码,一开始给 span 预留了最小的文字高度,所以才可以把父元素撑开,而 textarea 继承父元素的宽高,所以也会撑高,不需要根据页面大小做设置。另外我这个评论输入框是没有做这个效果的,是属于第二种右下角可以下拉伸缩的,下个新版博客会做适应。