[转载]自适应高度输入框
初步实现代码如下:
textarea {
width: 100%;
height: 92px;
padding: 20px;
line-height: 50px;
resize: none;
outline: none;
border: 1px solid #ccc;
background: #eee;
font-size: 32px;
box-sizing: border-box;
}
复制代码
<textarea id="textarea"></textarea>
复制代码
var $textarea = document.getElementById('textarea');
$textarea.addEventListener('input', function() {
// 总高度 = scrollHeight + 上下边框的宽度(1px * 2)
$textarea.style.height = $textarea.scrollHeight + 2 + 'px';
});
复制代码
然而,当内容高度缩减时,输入框的高度并没有跟随缩减。
由于根据scrollHeight设置的元素高度的存在,即使内容高度缩减,此时scrollHeight也不会低于元素高度。所以,在做自适应高度缩减时就无法直接通过同步scrollHeight来实现,而是要先清掉高度样式:
$textarea.addEventListener('input', function() {
// 清除原来高度
$textarea.style.height = '';
$textarea.style.height = $textarea.scrollHeight + 2 + 'px';
});
复制代码
实现后发现,输入到临近换行处,内容高度提前增高了。
调试后发现,清掉高度样式后,textarea恢复到原来的高度,此时内容超过textarea高度,因此会出现滚动条。滚动条会占据一定的空间,导致一行能容纳的字符减少,于是就提前换行了(如下图所示)。而因为在清理高度样式后,又立刻把高度设为新的scrollHeight,所以在界面上没有体现出现。
要解决这个问题,只需要把滚动条隐藏掉。
textarea {
overflow: hidden;
}
复制代码
虽然功能是做出来了,但是性能上还有优化的余地。因为当前的做法,相当于每次输入都要同步高度。如果高度没有发生变化,这个同步操作是没有意义的。所以,优化的思路就在于如何检查内容高度是否发生了变化:
- 内容增加时,scrollHeight有可能会发生变化,所以可以记录上一次的scrollHeight,并与当前的scrollHeight对比,有变化时才设置高度样式。
- 内容减少时,没有有效的方式可以知道内容高度是否有变更(scrollHeight不会减少),所以这种情况目前无法优化。
实现代码如下:
var $textarea = document.getElementById('textarea');
var lastLength = 0;
var lastHeight = 0;
$textarea.addEventListener('input', function() {
var currentLength = $textarea.value.length;
// 判断字数如果比之前少了,说明内容正在减少,需要清除高度样式,重新获取
if (currentLength < lastLength) {
$textarea.style.height = '';
}
var currentHeight = $textarea.scrollHeight;
// 如果内容高度发生了变化,再去设置高度值
if (lastHeight !== currentHeight || !$textarea.style.height) {
$textarea.style.height = currentHeight + 2 + 'px';
}
lastLength = currentLength;
lastHeight = currentHeight;
});
自己写的一个,有点bug,聚焦的时候输入框没清空 <div class="list-group-textarea" id="groupAreaEle" :value="desc" placeholder="填写聚会介绍,详细介绍主题、费用、流程等" v-on:input="onInputDesc | debounce 500" contenteditable="true"></div> <div class="list-blank"></div> <span class="counter" v-html="teatareaWordCount"></span> .list-group-textarea { width:100%; min-height:shift(138); font-size:shift(26); font-weight:400; color:rgba(50,51,51,1); line-height:shift(37); padding-top:shift(27); background:rgba(249,249,249,1); outline: 0 none; overflow:hidden; box-sizing:border-box; -webkit-user-select:text; -webkit-user-select:auto; &:empty:before { content: attr(placeholder); letter-spacing: 0; text-align: justify; font-size:shift(26); font-weight:400; color:rgba(205,205,205,1); } &:focus { content: none; } } .list-blank{ width:100%; height:shift(102); margin:0; padding:0; } .counter { position: absolute; right: 0; font-size: shift(24); line-height: shift(33); color: #aaaaaa; font-weight:400; }