美文网首页
textarea实现高度自适应

textarea实现高度自适应

作者: LM林慕 | 来源:发表于2019-12-09 09:46 被阅读0次

    业务场景

    需求:当用户在输入框中输入内容时,原有设计是最多输入三行,超出时会有滚动条,现改为不需要滚动条,输入的内容为多高,textarea就是多高。
    思路:

    1. 使用contenteditable属性用div模拟textarea文本框;
    2. javascript实现。

    技术实现

    1. 使用div模拟textarea文本框实现高度自适应

    1. 给块状元素加contenteditable="true"实现可编辑,如:
    <div contenteditable="true"></div>
    

    contenteditable属性虽是HTML5里面的内容,但是IE很早就支持此标签属性了。所以,兼容性方面是不用太担心的。

    需求:如何实现模拟placeholder?

    在项目中,我是采用定位的方式,给可编辑的div加了一个同级标签spandiv/span的父级相对定位,span绝对定位,定位的位置和可编辑的div在同一位置。

    // 技术栈:vue
    // html
    // 因为在移动端模拟的placeholder是两行,所以加了一个最小高度
    <div>
      <div contenteditable="true" @input="questionProject" ref="question" :style="!questionProject?'minHeight:1.12rem':''"></div>
      <span class="iplaceholder" v-show="!questionProject">聚焦于技术经理在管的重点项目,包括疑难、应收项目,问题描述、处理进展</span>
    </div>
    

    2. 简单版的JavaScript实现,如不考虑兼容问题,已可满足使用

    textarea加一个keyupkeydown事件,代码很简单,如下:

    // 技术栈:vue,布局方式:rem
    // html
    <textarea placeholder="请输入内容" v-model.trim="xxxxxx" @keydown="autoTextarea"></textarea>
    // js
    autoTextarea = (e) => {
      let elem = e.target
      let rootFontSize = parseFloat(document.documentElement.style.fontSize)
      elem.style.height = 'auto'
      elem.scrollTop = 0 // 防抖动
      elem.style.height = elem.scrollHeight / rootFontSize + 'rem'
    }
    

    3. 兼容版JavaScript实现

    我看了好几篇文章,几乎都是互相借鉴的,这个方法确实考虑的相对周全,具体代码如下:

    // js
    /**
    * 文本框根据输入内容自适应高度
    * @param                {HTMLElement}        输入框元素
    * @param                {Number}                设置光标与输入框保持的距离(默认0)
    * @param                {Number}                设置最大高度(可选)
    */
    
    var autoTextarea = function (elem, extra, maxHeight) {
      extra = extra || 0;
      var isFirefox = !!document.getBoxObjectFor || 'mozInnerScreenX' in window,
        isOpera = !!window.opera && !!window.opera.toString().indexOf('Opera'),
        addEvent = function (type, callback) {
          elem.addEventListener ?
            elem.addEventListener(type, callback, false) :
            elem.attachEvent('on' + type, callback);
        },
        getStyle = elem.currentStyle ? function (name) {
          var val = elem.currentStyle[name];
    
          if (name === 'height' && val.search(/px/i) !== 1) {
            var rect = elem.getBoundingClientRect();
            return rect.bottom - rect.top -
              parseFloat(getStyle('paddingTop')) -
              parseFloat(getStyle('paddingBottom')) + 'px';
          };
    
          return val;
        } : function (name) {
          return getComputedStyle(elem, null)[name];
        },
        minHeight = parseFloat(getStyle('height'));
    
      elem.style.resize = 'none';
    
      var change = function () {
        var scrollTop, height,
          padding = 0,
          style = elem.style;
    
        if (elem._length === elem.value.length) return;
        elem._length = elem.value.length;
    
        if (!isFirefox && !isOpera) {
          padding = parseInt(getStyle('paddingTop')) + parseInt(getStyle('paddingBottom'));
        };
        scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
    
        elem.style.height = minHeight + 'px';
        if (elem.scrollHeight > minHeight) {
          if (maxHeight && elem.scrollHeight > maxHeight) {
            height = maxHeight - padding;
            style.overflowY = 'auto';
          } else {
            height = elem.scrollHeight - padding;
            style.overflowY = 'hidden';
          };
          style.height = height + extra + 'px';
          scrollTop += parseInt(style.height) - elem.currHeight;
          document.body.scrollTop = scrollTop;
          document.documentElement.scrollTop = scrollTop;
          elem.currHeight = parseInt(style.height);
        };
      };
    
      addEvent('propertychange', change);
      addEvent('input', change);
      addEvent('focus', change);
      change();
    };
    
    //html
    <textarea id="textarea" placeholder="回复内容"></textarea>
    <script>
      var text = document.getElementById("textarea");
      autoTextarea(text);// 调用
    </script>
    

    总结

    需使用的小伙伴可比较一下,我在项目里面使用的是第一种和第二种方法,因为我们做的是基于webview的混合开发(内嵌vue SPA),不需要考虑那么多的兼容问题,如果需要考虑更过兼容问题的话,可以尝试使用第三种方法。

    相关文章

      网友评论

          本文标题:textarea实现高度自适应

          本文链接:https://www.haomeiwen.com/subject/gmfbgctx.html