初步实现代码如下:
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;
}