编写自适应高度的 textarea

文本框是很罕见的输入控件,我置信只需写过表单的一定打仗过 textarea 这个元素。

OK。然则如今产物司理说了:须要这个文本框能够依据用户输入内容自适应其高度。

height: auto

有些初学者能够会想:自适应高度不就是 height: auto 么?但是你想一下,一个 textarea 没有手工给它指定过款式,不应该就默许是 height: auto 么?然则它照样有本身的初始高度,并没有像一个 div 那样高度为 0。

div 差别,textarea 的默许高度不是依据其内容自适应,而是由属性 rows 指定,其默许值是 2rows 这个属性(Attribute)只接收正整数,指定其他值浏览器会疏忽掉其值,比方你写 rows="auto" 那末 rows 就是 2,rows="0" 也是 2。

《编写自适应高度的 textarea》

所以指定 height: auto 是行不通的,height 属性必需人工指定其值。

scrollHeight

遇到过这个题目的同砚(比方当初的笔者),一定想到过 scrollHeight 这个 DOM 属性。主意很简朴,当用户输入的文本凌驾了文本框本身高度时不是会涌现滚动条嘛,那末自然而然就可以想到 scrollHeight 这个属性。scrollHeight 就应该是用户输入文本的实在高度,最少凌驾文本框既定高度时是如许。

那末题目来了:假如没凌驾呢?

OK 我晓得你会先指定 rows="1" 让文本框默许高度只要一行。然则斟酌这类状况:用户先输入了许多行文本

《编写自适应高度的 textarea》

然后删除了一段:

《编写自适应高度的 textarea》

scrollHeight 值没有变化。MDN 上说了:

没有垂直滚动条的状况下,scrollHeight值与元素视图添补一切内容所须要的最小值clientHeight雷同

scrollHeight 确切会跟着用户输入内容若干而增减,然则仅限于涌现滚动条的状况,关于题设这个状况必定不实用,由于需求就是不能涌现滚动条(严格来说是超越可视地区)。你能够在猎取 scrollHeight 的值之前先把文本框高度设为 0 强迫让滚动条涌现,然则如许能够使页面发作闪灼,而且机能也低。

split(‘\n’)

DOM 属性靠不住,那我本身算文本高度不行吗?说我拿出一切文本,按换行符拆分,看有若干行,行数 * 行高 不就是终究文本高度吗?

额。。。当文本没有折行的状况下是如许。。。

contenteditable

contenteditable 确切是一个(相对)可行的计划,然则作为一个踩过坑的先行者劝慰你:不到万不得已,contenteditable 不要碰。这个玩意各个浏览器完成都不一样,种种奇葩行动,光一个换行符就充足熬煎你半天。

固然这里还没有到那末庞杂的田地,然则你得先会把“复制——粘贴”过去的款式去掉才行

《编写自适应高度的 textarea》

笔者的要领

说了那末多空话,那末终究该怎么办呢?这里笔者供应一种要领。

固然起首声明:笔者的要领未必是最简朴的,若有别的更简朴的计划迎接留言提出。

我们想一下,textarea 不能根据内容自适应高度,div 能够啊,能不能先把文本填到一个 div 里,div 的高度就应该是文本框所需高度(当 paddingline-height 等款式都一致的状况下),这时候猎取 div 的高度赋值给文本框高度不就行了吗。

就是如许的思绪。我们也不须要特地运用 JS 猎取,只需让 div 把父元素撑起来,相对定位 textarea 元素让文本框占满全部父元素大小就好了。

直接上代码:

<style>
  #parent {
    width: 500px;
    font: 12px monospace;
    position: relative;
  }
  #dummy {
    padding: 2px;
    border: 1px solid;
    visibility: hidden;
  }
  #dummy::after {
    content: "\A";
  }
  #textarea {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    resize: none;
    width: 100%;
    font: inherit;
  }
</style>
<div id="parent">
  <div id="dummy"></div>
  <textarea id="textarea"
            oninput="document.getElementById('dummy').textContent = this.value"></textarea>
</div>

这里检察运转效果:https://codepen.io/CarterLi/p…

三个要点:

  1. 字体相干款式 #dummytextarea 两元素必需完全一致,差一点就可以够涌现二者高度对不上的状况。
  2. #dummywhite-space: pre-wrap 能干。不然会涌现 HTML 中吞空格、换行符的状况。
  3. 就算有了 white-space: pre-wrap,HTML 仍然会吞掉末了的换行符。解决计划是在 #dummy 末了插进去一个换行符元素。能够是 <br />,也能够是一个伪元素。伪元素中换行符的写法是 \A(即换行符的 ASCII 码 10 的十六进制示意。不能写 \n

代码中是用 JS 给 #dummy 赋值。项目中假如你用 vuejsangular 等 MVVM 框架,直接把文本框的值绑定到 div 上就好,异常轻易。

假如你要限定文本框的最大最小高度,在 #dummy 上直接设置 min-height max-height 即可。

末了说一句:把 textarea 盖到一个 div 上的做法还能够简朴的完成文本框的语法高亮,读者能够想一想怎么做。

    原文作者:CarterLi
    原文地址: https://segmentfault.com/a/1190000018268648
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞