封装一个自动resize的textarea(Angular)

autoresize.gif

>> 前往stackblitz编辑代码

核心思路

textarea-autosize.jpg

  1. 建立两个textarea,这里暂取名为text和text1。(最后会将text1隐藏,调试时先让text1显示)。
  2. 将text1的高度和rows设置为仅能输入一行,这么作是为了用元素的scrollHeight表示其内容的高度。
  3. 用户将在text中输入,咱们将输入的值同步绑定到text1中,并经过text1的scrollHeight获取输入内容的高度,并同步改变text的height。

实现

准备工做

  1. 首先,新建一个模块textarea.module.ts,并引入FormsModule,由于接下来将会用到ngModel进行双向数据绑定。
  2. 在模块内新建一个组件textarea。
  3. 在模块内exports出该组件。之后只需引入该模块便可使用该组件。

实做

  1. 在组件模板内写两个textarea,并标记为模板变量#text和#text1。
  2. 在模板中数据绑定,并监听数据变化。css

    <textarea (ngModelChange)="onChange()" [(ngModel)]="val" #text class="autosize"  rows="1"></textarea>
    <textarea class="autosize hidden"  rows="1" [value]="val" #text1></textarea>
  3. 在textarea.component.ts中增长一个输入属性和一个输出属性。输入属性maxHeight表示textarea的heigh的极限。输出属性valChange将会在用户输入的数据变化时发出数据。浏览器

    @Input('max-height') maxHeight = 100;
     @Output('valChange') valChange = new EventEmitter();
  4. 在textarea.component.ts中写模板中调用的onChange方法。让text的高度始终等于text1的scrollHeight;这里是直接操做Dom,建议最好使用Renderer2进行dom的修改。app

    onChange() {
    this.reset();
    setTimeout(() => {
      this.valChange.emit(this.val);
      this.reset();
    }, 0)
    
    }
    reset() {
        this.text1.nativeElement.style.width = (this.text.nativeElement.scrollWidth + 2) + 'px';
        if (this.text1.nativeElement.scrollHeight < this.maxHeight) {
          this.text.nativeElement.style.height = (this.text1.nativeElement.scrollHeight + 2) + 'px'
        }
    }

    注意1:这里获取scrollwidth的目的是由于不一样的浏览器对滚动条的呈现逻辑有差别,咱们在css中已经设置了text1的overflow=hidden,始终不会让text1出现滚动条,所以咱们须要让他的宽度始终等于text1的宽度,以保证当text出现滚动条是他的的宽度也保持一致,从而让scrollHeight能够完美映射到text,不然会出现text中明明尚未达到边界,高度就自行变化了。
    注意2:setTimeout中的逻辑是为了应付事件环,由于咱们监听的是text的变化,当text中输入变化时,text1中经过数据绑定获得的值每每尚未改变,须要等一个节拍。dom

使用

  • 只须要监听输出属性valChange,并传入$event就能够获取用户输入了。
  • 若有须要能够在此基础上继续扩展,使其兼容响应式表单。this

    <app-yu-textarea  (valChange)="onChange($event)" max-height='100' class="tex"></app-yu-textarea>
  • 修改样式须要注意选择器的权重。
相关文章
相关标签/搜索