需求

  • 实现一个输入框,高度可以随着输入文字的增加而自动增高,类似于微信输入
  • 输入为空时,显示placeholder
  • 字数限制maxlength

方法1:使用textarea配合工具函数autosize实现高度自适应的输入框(支持IE9+),具体代码如下:

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <style type="text/css">
            * {
                margin: 0;
                padding: 0;
            }
            textarea {
                resize: none;
            }
        </style>
    </head>
    <script type="text/javascript" src="js/autosize.min.js"></script>
    <body>
        <textarea id="textarea" rows="1" placeholder="请输入内容..." maxlength="50"></textarea>
    </body>
    <script type="text/javascript">
        autosize(document.querySelector('#textarea'));
    </script>
    </html>

注:因为textarea的默认高度为rows=2,所以需要将textarea的rows设置为1

方法2:div加属性contenteditable=true

我们知道可以将div的contenteditable设置伪true,将其变为可输入状态。代码如下:

<div contenteditable="true"></div>

这样就满足了我们的第一个需求——高度自适应。但是在手机上测试会发现第一个问题,iOS上面无法输入。经过查找资料,发现只需要为其添加如下样式即可:

 div{
    user-select:text;
    -webkit-user-select:text;
}

实现placeholder

使用css+js实现 placeholder,思路:根据输入通过动态添加class,模拟placeHolder的行为,代码如下:

// css
.textarea {
    width: 400px;
    min-height: 20px;
    max-height: 300px;
    _height: 120px;
    margin-left: auto;
    margin-right: auto;
    padding: 3px;
    outline: 0;
    border: 1px solid #a0b3d6;
    font-size: 12px;
    line-height: 24px;
    padding: 2px;
    word-wrap: break-word;
    overflow-x: hidden;
    overflow-y: auto;
    border-color: rgba(82, 168, 236, 0.8);
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6);
    position: relative;
    user-select: text;
    -webkit-user-select: text;
}
.placeholder:before {
    content: '请输入内容...';
    line-height: 30px;
    position: absolute;
    left: 5px;
    top: 0;
    z-index: 1;
}
// html
<div class="textarea placeholder" contenteditable="true" data-placeholder="请输入内容..." data-length="10"><br /></div>
// js
var oInputBox = document.querySelector('.textarea');
oInputBox.oninput = oInputBox.onpropertychange = function (ev) {
    var innterStr = oInputBox.innerText;
    var _this = this;

    // placeholder
    if (innterStr.length == 0) {
        _this.classList.add('placeholder');
    } else {
        _this.classList.remove('placeholder');
    }
};

到此,我们已经实现了第二个需求——可以设置placeholder

实现maxlength

同样的,我们也不能通过直接设置maxlength来满足需求。所以通过监听input事件来实时计算长度。

var oInputBox = document.querySelector('.textarea');
oInputBox.oninput = oInputBox.onpropertychange = function (ev) {
    var innterStr = oInputBox.innerText;
    var _this = this;

    // maxlength
    var len = parseInt(_this.getAttribute('data-length'));
    if (innterStr.length > len) {
        oInputBox.innerText = innterStr.substring(0,len);
    }
};

以上代码看上去没有问题,但是会发现光标会跑到最前方,这样就会造成不好的用户体验,甚至出现Bug。所以在截取了最大长度的用户输入后,我们还需要将光标放到最后。完整JS代码如下:

var oInputBox = document.querySelector('.textarea');
oInputBox.oninput = oInputBox.onpropertychange = function (ev) {
    var innterStr = oInputBox.innerText;
    var _this = this;

    // placeholder
    if (innterStr.length == 0) {
        _this.classList.add('placeholder');
    } else {
        _this.classList.remove('placeholder');
    }
    // maxlength
    var len = parseInt(_this.getAttribute('data-length'));
    if (innterStr.length > len) {
        oInputBox.innerText = innterStr.substring(0,len);
    }

    // div innerText重新赋值之后的光标问题

    if(navigator.userAgent.indexOf('MSIE') > -1) {
        var range = document.selection.createRange();
        _this.last = range;
        range.moveToElementText(_this);
        range.select();
        document.selection.empty(); //取消选中
    } else {
        var range = document.createRange();
        range.selectNodeContents(_this);
        range.collapse(false);
        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    }
};

到此为止,一个可以自动增加高度,并且支持placeholder和maxlength的输入框就完成了。

要点总结:

  • 方法1:autosizejs方法通过监听textarea的input、keyup事件动态的获取其scrollHeight,计算出实际高度并配合overflow属性的改变来动态的改变 textarea的高度,此方法使用的时候需要注意的是textarea的rows属性要设置为1,两行以内的高度自适应就会出现问题;兼容性:IE9+
  • 方法2:div设置contentEditable为true后,输入或删除内容时,其高度本身就会随着内容的变化而变化,我们需要解决的问题只是在输入过程中光标的位置问题;兼容性:IE11及其他高级浏览器

参考资料:

autosize

高度自适应输入框