You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于原生JS实现随文本内容自适应高度的textarea(无jQuery)

Hey there! 作为刚从后端转过来入门原生JS的开发者,你遇到的这个问题其实非常典型——动态生成的元素没法绑定页面加载时就定义好的事件,毕竟代码执行的时候,那个textarea还不存在呢!别担心,咱们一步步来解决它~

问题根源

你原来的自适应高度代码是在页面加载时执行的,这时候document.getElementById('reply-message')根本找不到元素,自然没法给它绑定keyup事件。只有当用户点击按钮创建textarea之后,我们才能给这个新生成的元素绑定事件。

解决方案1:创建textarea后立即初始化自适应逻辑(推荐新手)

最直观的方法就是把自适应高度的逻辑封装成一个函数,每次创建完textarea之后,立刻调用这个函数给它绑定事件。这样就能保证事件只绑定到已经存在的元素上。

修改后的完整代码如下:

JavaScript部分

var replyBtns = document.querySelectorAll('[id=rep]');
for(var i = 0; i < replyBtns.length; i++) {
  replyBtns[i].addEventListener('click', function(e) {
    e.preventDefault();
    // 移除已存在的回复框
    var existingTextarea = document.getElementById("reply-message");
    if (existingTextarea) {
      existingTextarea.parentNode.removeChild(existingTextarea);
      // 顺便移除对应的隐藏div,避免DOM冗余
      var hiddenDiv = document.querySelector('.hiddendiv');
      if (hiddenDiv) {
        hiddenDiv.parentNode.removeChild(hiddenDiv);
      }
    }
    // 创建新的textarea
    var replyBox = document.createElement('textarea');
    replyBox.setAttribute('id', 'reply-message');
    replyBox.setAttribute('placeholder', 'Reply');
    this.parentNode.insertAdjacentElement('beforeend', replyBox);
    
    // 关键:给新创建的textarea初始化自适应逻辑
    setupAutoResize(replyBox);
  }, false);
}

// 封装自适应高度的函数
function setupAutoResize(textarea) {
  // 创建隐藏的克隆div
  let hiddenDiv = document.createElement('div');
  hiddenDiv.classList.add('hiddendiv');
  document.body.appendChild(hiddenDiv);

  // 定义更新高度的逻辑
  function updateHeight() {
    let content = textarea.value;
    // 加上换行是为了让高度计算更准确,避免内容顶到边界
    hiddenDiv.innerHTML = content + '\n\n';
    textarea.style.height = hiddenDiv.getBoundingClientRect().height + 'px';
  }

  // 绑定输入事件:keyup + input(覆盖粘贴、拖拽等非键盘输入场景)
  textarea.addEventListener('keyup', updateHeight, false);
  textarea.addEventListener('input', updateHeight, false);
  
  // 初始化一次高度,确保刚创建时就和占位符/初始内容匹配
  updateHeight();
}

CSS部分(保持你原来的即可)

textarea#reply-message {
  display: block;
  border: none;
  color:#306654;
  font-size:120%;
  padding: 5px 10px;
  line-height: 20px;
  width:550px;
  height: 20px;
  border-radius: 6px;
  overflow: hidden;
  resize: none;
}

.hiddendiv {
  position: absolute;
  left: -9999px;
  visibility: hidden;
  white-space: pre-wrap;
  width: 550px;
  height: 20px;
  font-size: 120%;
  padding: 5px 10px;
  word-wrap: break-word;
  overflow-wrap: break-word;
}

解决方案2:事件委托(适合多动态元素场景)

如果你的页面会频繁创建/删除textarea,或者有多个类似的动态元素,用事件委托会更高效。原理是利用事件冒泡,把事件绑定到父元素(甚至document)上,当事件触发时判断目标元素是不是我们的textarea。

示例代码:

// 页面加载时就绑定事件到document
document.addEventListener('keyup', handleTextareaResize);
document.addEventListener('input', handleTextareaResize);

function handleTextareaResize(e) {
  // 只处理id为reply-message的textarea
  if (e.target.id !== 'reply-message') return;
  
  let txt = e.target;
  let hiddenDiv = document.querySelector('.hiddendiv');
  
  // 如果隐藏div不存在,创建它
  if (!hiddenDiv) {
    hiddenDiv = document.createElement('div');
    hiddenDiv.classList.add('hiddendiv');
    document.body.appendChild(hiddenDiv);
  }
  
  let content = txt.value;
  hiddenDiv.innerHTML = content + '\n\n';
  txt.style.height = hiddenDiv.getBoundingClientRect().height + 'px';
}

这种方法不需要每次创建textarea都绑定事件,一次绑定就能处理所有未来生成的同类型元素,适合更复杂的场景。

小优化建议

  • 确保.hiddendiv的样式和textarea#reply-message完全一致(你已经做到了),这样高度计算才会准确。
  • 移除textarea时顺便删掉对应的隐藏div,避免DOM里积累无用元素(解决方案1里已经加了这个逻辑)。
  • 绑定input事件,因为keyup覆盖不了粘贴、鼠标拖拽输入等场景。

这样修改之后,你的textarea就能正常实现自适应高度啦!

内容的提问来源于stack exchange,提问作者Hassan Baig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:41:16