封裝一個自動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>
  • 修改樣式須要注意選擇器的權重。
相關文章
相關標籤/搜索