textarea 动态宽高(根据内容动态撑开宽高)

1,178 阅读1分钟

temp.gif

  • 推荐通过 div 实现 input、textarea 输入框,如果自定义的也需要动态计算宽高度,下面的方式可以参考,计算行高加间距就行了,下面是系统自带的 textarea

  • 重点:计算的 span 标签属性需要与 输入框 的字体属性保持一致,这样才能算的精准。

  • 案例代码,标签虽然有默认属性,但是为了能够通过 JS 取到值,所以必须手动写一遍样式属性,html 一样带上 style 即可。

    <script>
      // 文本输入框(必备属性,主要是字体相关属性)
      // var inputEl = document.createElement('textarea')
      // inputEl.value = '默认文字'
      // inputEl.rows = 1
      // inputEl.style.width = '20px'
      // inputEl.style.fontSize = '20px'
      // inputEl.style.fontWeight = 400
      // inputEl.style.fontFamily = 'monospace'
      // inputEl.style.wordBreak = 'break-all'
      // inputEl.style.whiteSpace = 'normal'
      // document.body.appendChild(inputEl)
      // // 有默认内容初始化尺寸
      // inputSizeChange(inputEl)
    
      // 文本输入框(案例)
      var inputEl = document.createElement('textarea')
      inputEl.rows = 1
      inputEl.style.width = '20px'
      inputEl.style.fontSize = '20px'
      inputEl.style.fontWeight = 400
      inputEl.style.fontFamily = 'monospace'
      inputEl.style.padding = 0
      inputEl.style.border = 'none'
      inputEl.style.backgroundColor = 'red'
      inputEl.style.outline = 'none'
      inputEl.style.resize = 'none'
      inputEl.style.wordBreak = 'break-all'
      inputEl.style.whiteSpace = 'normal'
      document.body.appendChild(inputEl)
    
      // 输入监听
      inputEl.oninput = (e) => {
        // 动态调整宽高
        inputSizeChange(inputEl, 23)
      }
      // 获取焦点
      setTimeout(() => {
        // 获取焦点
        inputEl.focus()
        inputEl.select()
      }, 0)
    
      // 计算输入框大小
      // input:(必填)输入框
      // rowh:(必填)当没有内容时默认高度,如果不传当没有内容时会没高度
      // colw:(可选)当没有内容时默认宽度,如果不传宽度会很窄
      function inputSizeChange (input, rowh, colw) {
        // 输入的内容
        const text = input.value.replaceAll('\r','').replaceAll('\n\n','\n')
        // 创建一个 span
        const span = document.createElement('span')
        // 隐藏
        span.style.opacity = 0
        // 清空间距
        span.style.padding = 0
        span.style.margin = 0
        // 保证能正常撑开
        span.style.display = 'inline-block'
        // 字体属性跟输入框保持一致
        span.style.wordBreak = input.style.wordBreak
        span.style.whiteSpace = input.style.whiteSpace
        span.style.fontSize = input.style.fontSize
        span.style.fontWeight = input.style.fontWeight
        span.style.fontFamily = input.style.fontFamily
        // 将输入内容分割成行数组
        var texts = text.split('\n')
        // 插入标签元素
        var innerHTML = ''
        // 便利组装
        texts.forEach(function (text, index) {
          // 根据情况进行组装
          if (index === 0) {
            // 0 行直接使用
            innerHTML += text
          } else if (!text.length) {
            // 空行则手动加换行符与临时计算内容
            innerHTML += '<br/><span>s</span>'
          } else {
            // 非空行则回车加内容
            innerHTML += ('<br/>' + text)
          }
        })
        // 将回车替换成换行符
        span.innerHTML = innerHTML
        // 添加到页面上才能得到尺寸
        document.body.appendChild(span)
        // 获取 span 的宽高,+ 5 在刚好的宽度上多 5px 保证光标的显示,要不然宽度不够会自动到下一行
        var width = span.clientWidth + 5
        var height = span.clientHeight
        // 最后一行是否为空行
        var isEmptyLine = !texts[texts.length - 1].length
        // 就只剩一行并且是空行,则需要使用默认匡高
        if (texts.length === 1 && isEmptyLine) {
          if (colw) { width = colw }
          if (rowh) { height = rowh }
        }
        // 设置宽高
        input.style.width = `${width}px`
        input.style.height = `${height}px`
        // 移除计算的 span
        document.body.removeChild(span)
      }
      // 支持全部替换(部分浏览器不自带)
      String.prototype.replaceAll = function (s1, s2) {
        return this.replace(new RegExp(s1, "gm"), s2)
      }
    </script>