重点实现了默认开始的时候高度一致,不会导致开始的时候textarea的高度展开的问题
textarea实现自动增加减少高度,
<textarea #textarea
class="smart-textarea"
[(ngModel)]="content"
(input)="adjustHeight()"
placeholder="Start typing..."
></textarea>
.smart-textarea {
width: 100%;
min-height: 1.2lh; /* 使用lh单位确保基础高度 */
line-height: 1.6; /* 必须与hiddenDiv的line-height一致 */
margin: 0;
box-sizing: border-box;
font-family: inherit;
font-size: 16px;
resize: none;
overflow-y: hidden;
}
.height-calculator {
position: absolute;
visibility: hidden;
white-space: pre-wrap;
word-wrap: break-word;
pointer-events: none;
}
//.smart-textarea {
// transition: height 0.15s ease-out;
//}
@ViewChild('textarea') textareaRef!: ElementRef<HTMLTextAreaElement>;
content = '';
private calculator!: HTMLElement;
private baseHeight = 0;
// 监听窗口变化,调整高度
@HostListener('window:resize')
onWindowResize() {
this.adjustHeight(true);
}
ngAfterViewInit() {
this.initHeightCalculator();
this.setBaseHeight();
this.adjustHeight(true); // 强制初始调整
}
ngOnDestroy() {
if (this.calculator && this.calculator.parentNode) {
document.body.removeChild(this.calculator);
}
}
private initHeightCalculator() {
this.calculator = document.createElement('div');
this.calculator.className = 'height-calculator';
const textarea = this.textareaRef.nativeElement;
const textareaStyle = window.getComputedStyle(textarea);
// 安全复制样式属性,避免 TS7015 错误
const styleProperties: (keyof CSSStyleDeclaration)[] = [
'font', 'letterSpacing', 'wordSpacing', 'textTransform',
'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft',
'borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth',
'width', 'boxSizing'
];
for (const prop of styleProperties) {
const value = textareaStyle[prop];
if (typeof value === 'string') {
this.calculator.style.setProperty(
prop.toString(),
value
);
}
}
this.calculator.style.overflow = 'hidden';
this.calculator.style.position = 'absolute';
this.calculator.style.visibility = 'hidden';
this.calculator.style.whiteSpace = 'pre-wrap';
this.calculator.style.wordWrap = 'break-word';
document.body.appendChild(this.calculator);
}
private setBaseHeight() {
// 获取真实的单行高度(包括 padding)
this.calculator.textContent = ' ';
this.baseHeight = this.calculator.offsetHeight;
// 设置 textarea 最小高度为单行高度
this.textareaRef.nativeElement.style.minHeight = `${this.baseHeight}px`;
}
adjustHeight(force = false) {
const textarea = this.textareaRef.nativeElement;
if (!force && textarea.value === '') return;
// 同步宽度以防止换行计算错误
this.calculator.style.width = `${textarea.clientWidth}px`;
// 确保换行符被正确渲染
this.calculator.textContent = textarea.value + '\n';
// 计算新高度并设置到 textarea 上
const newHeight = Math.max(this.calculator.offsetHeight, this.baseHeight);
textarea.style.height = 'auto';
textarea.style.height = `${newHeight}px`;
}