封裝一個自動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. 在模板中數據綁定,並監聽數據變化。

    <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的修改。

     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中通過數據綁定得到的值往往還沒有改變,需要等一個節拍。

使用

  • 只需要監聽輸出屬性valChange,並傳入$event就可以獲取用戶輸入了。
  • 如有需要可以在此基礎上繼續擴展,使其兼容響應式表單。

    <app-yu-textarea  (valChange)="onChange($event)" max-height='100' class="tex"></app-yu-textarea>
  • 修改樣式需要注意選擇器的權重。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章