textarea高度自适应的两种方案

时间:2025-04-06 16:45:31

方案一

html5 Textarea 元素

1. 自动获得焦点

点击编辑自动获得焦点后光标跳转到了最前面,why?

查文档 MDN,textarea元素存在selectionEndselectionStart的属性用来表示选中的文本开始位置和结束位置,DOM接口实例是 htmlTextAreaElement, 它具有 setSelectionRange 方法,用来选中输入框中的文本,用法:

(selectionStart, selectionEnd, [optional] selectionDirection);

那么我们只要做到selectionStart === selectionEnd ===  , 这样光标就选中到最末尾。

("click", function() {
  ("hidden");
  (textarea, edit);
   = "这是需要编辑的信息";
  ();
  //  = ;

  (
    ,
    
  );
});

2. 自适应高度

当不设置高度时换行会出现滚动条,所以只要让textarea滚动条消失,让其height = scrollHieght, 那么如何监听textarea的变化,则需要input事件,让textarea高度动态等于它的scrollHeight即可,代码如下:

("input", function() {
     = `${}px`;
});

为什么每次输入都会使得高度增加(每次增加4px),经过测试Safari同样也是这个效果,Firefox符合预期高度不异常增加,查看Chrome控制台发现(查看 chromium) textarea内置了很多样式,尝试将去掉padding后,可以正常随着内容增加高度自适应了。

<style>
textarea {
  padding: 0;
}
</style>
<textarea></textarea>
<script>
const textarea = ("textarea");
("input", function(e) {
   = `${}px`;
});
</script>

为什么去掉padding值,输入后高度就不增加了?(未找到合理的解释,欢迎留言讨论解答)

但是删除文本的情况下height并未能自动缩放,分析原因, 当删除文本换行的时候scrollHeight的大小并未发生改变,scrollHeight作为只读属性( MDN-文档),如何让scrollHeight高度重新计算哪?只有改变高度,于是:

("input", function(e) {
   = "inherit";
   = `${}px`;
});

到此高度自适应输入内容完成,但是每次换行的闪动很难受,transition走一波,

textarea {
  overflow: hidden;  // 防止换行出现滚动条闪动
  padding: 5px 10px;
  box-sizing: border-box;
  transition: all 0.2s linear;
}

结果transition并没效果,原因height初始值或者参考值必须为数值过渡动画才会生效,height设置为auto或者inherit动画不会生效, 所以折中的办法就是当删除的时候重新重置高度,输入时不需要重置,这样输入时动画生效, 删除没有动画, 暂时没想到更好的办法。

("keyup", function(e) {
  if ( === 8) {
     = "inherit";
     = `${}px`;
  } else {
     = `${}px`;
  }
});

3. 支持粘贴文本,图片等

textarea只能输入文本,无法实现粘贴图片。

(
  "paste",
  function(e) {
    ();
    (
      "paste",
      ,
      ,
      ("text/html"),
      ("text/plain"),
      ("text/Files")
    );
  },
  false
);

 

方案二

div contenteditable 替换textarea

1. 自动获得焦点

编辑div contenteditable为true,然后利用Range和Selection 光标移动到最后的效果。

("click", () => {
  ("contenteditable", true);
  ();
  const range = ();

  // range 包含的内容
  (textarea);

  // (, 0);
  // (, );

  // 起始位置是否相同
  (false);
  const sel = ();
  
  // 将所有的区域都从选区中移除。
  ();
  
  // 一个区域(Range)对象将被加入选区。
  (range);
});

2. 自适应高度

div contenteditable 天然支持根据输入来自适应高度。

3. 粘贴图片, 文本等

("paste", function(e) {
  ();
  const clipboardData =  || ;
  // 获取纯文本
  let text = ("text/plain");
  let file = ("text/plain");
  // (, ("text/Files"));

  // 插入img,可以做一些上传图片的一些操作
  insertImg(clipboardData);

  // 只输入纯文本
  ("insertText", false, text);
});