我正在尝试自动调整textarea
的大小,以使其适合其中的内容,但是单击Enter进入下一行后,我遇到了一个口吃的问题。我该如何解决?
有关StackBlitz示例,请参见此link
代码
this.form.valueChanges.subscribe(() => {
const textarea = this.myDiv.nativeElement;
textarea.addEventListener('keydown', function() {
setTimeout(() => {
this.style.cssText = 'height:auto; padding:0';
this.style.cssText = 'height:' + this.scrollHeight + 'px';
}, 0);
});
});
答案 0 :(得分:2)
addEventListener
在这里是多余的,因为valueChanges
已经在字段更改时通知您。而是使用ViewChild
参考myDiv
更新高度。
this.myForm.valueChanges.subscribe(value => {
this.myDiv.nativeElement.style.height = 'auto';
this.myDiv.nativeElement.style.height = `${this.myDiv.nativeElement.scrollHeight}px`;
});
然后将overflow: hidden
添加到CSS中,以使滚动条不显示。
textarea {
resize: horizontal;
overflow: hidden;
}
您可以保留resize: horizontal;
,但不再需要,因为它会自动调整大小。
这是StackBlitz上的一个有效示例。
答案 1 :(得分:1)
您要实现的目标是一个很老的技巧。我自己使用过,但尝试了另一种方法。
您每次在height = 0
进行每次击键来计算滚动高度时,为什么文本区域都是跳动的,所以您可以分配一个新的高度。
我计算了fontSize或lineHeight,并计算了行数和基于该行数调整的初始高度。因此,在每次击键时,您只是分配了高度,而没有使文本区域的高度为0
textareaProps = null;
getHeight(element) {
const lines = element.value.split(/\r\n|\r|\n/).length;
if(!this.textareaProps) {
const autoStyle = getComputedStyle(element);
const lineHeight = parseInt(autoStyle.lineHeight);
const adjust = parseInt(autoStyle.height) - lineHeight;
this.textareaProps = {adjust, lineHeight}
}
const { adjust, lineHeight } = this.textareaProps;
const height = lines * lineHeight + adjust;
return height + 'px';
}
您现在需要调用此方法以获取高度并将textarea元素作为arg传递。
element.style.cssText = 'height:' + getHeight(element) ;
编辑2
遗憾的是,以上解决方案仅在用户出现换行符时才有效。当输入巨大的行时,文本区域将自动换行,但不会增加高度。因此,引入一个代理html元素,该html元素的文本将与文本区域的值相同,并将提供可分配给文本区域的高度。
textareaProps = null;
getHeight(element) {
if(!this.textareaProps) {
const proxy = document.createElement('div');
const {padding, width, fontSize, height, lineHeight} = getComputedStyle(element);
const css = [
'position:absolute',
'visibility: hidden',
'pointer-events:none',
`width: ${width}`,
`padding:${padding}`,
`min-height: ${height}`,
`font-size:${fontSize}`,
`line-height:${lineHeight}`,
].join(';');
proxy.style.cssText=css;
this.textareaProps = {
proxy: document.body.appendChild(proxy),
adjust: (parseInt(fontSize))
};
}
const { proxy, adjust} = this.textareaProps;
proxy.innerText = element.value + '.';
return (proxy.offsetHeight + adjust) + 'px';
}
更新后的StackBlitz https://stackblitz.com/edit/next-line-view-child-ssnp4q
答案 2 :(得分:0)
对于在2021年左右仍在寻找答案的任何人,其内容已涵盖in the official Angular Material docs here。通过nativeElement
直接操作DOM是一种反模式。
<mat-label>Autosize textarea</mat-label>
<textarea matInput
cdkTextareaAutosize
#autosize="cdkTextareaAutosize"
cdkAutosizeMinRows="1"
cdkAutosizeMaxRows="5"></textarea>
</mat-form-field>
TS:
import {CdkTextareaAutosize} from '@angular/cdk/text-field';
import {Component, NgZone, ViewChild} from '@angular/core';
import {take} from 'rxjs/operators';
/** @title Auto-resizing textarea */
@Component({
selector: 'text-field-autosize-textarea-example',
templateUrl: './text-field-autosize-textarea-example.html',
styleUrls: ['./text-field-autosize-textarea-example.css'],
})
export class TextFieldAutosizeTextareaExample {
constructor(private _ngZone: NgZone) {}
@ViewChild('autosize') autosize: CdkTextareaAutosize;
triggerResize() {
// Wait for changes to be applied, then trigger textarea resize.
this._ngZone.onStable.pipe(take(1))
.subscribe(() => this.autosize.resizeToFitContent(true));
}
}