textarea實現高度自適應的理解

無妄''發表於2020-11-06

今天遇到個需求:要求 textarea 初始只顯示一行,當使用者輸入內容過多引起換行,或者手動敲Enter鍵換行時,textarea 內容區域自動撐開。

這個簡單,於是我敲下大致如下程式碼:

// html
<textarea id="codePath" rows="1"></textarea>

// js
let codePath = document.getElementById('codePath');

codePath.addEventListener('input', function () {
     let _this = this;
     _this.style.height = `${_this.scrollHeight}px`;
})

頁面初始化的時候如下:
在這裡插入圖片描述
輸入長段內容或手動按Enter鍵後,如下:
在這裡插入圖片描述
看起來似乎是完美實現了需求,但是當我刪除一部分內容的時候,就傻眼了:
在這裡插入圖片描述
沒錯,使用者輸入的時候,用 scrollHeight 去改變 height 的值,textarea內容區域會隨著輸入內容行數增加而撐開,但是不會隨著輸入內容行數的減少而縮回去。

網上找了些解決方案,無非就是用一大段指令碼,來建立一個隱藏的 div 元素,再同步 div 的 innerHTML 和 textarea 的 value,再把 div 高度賦給 textarea;或者隱藏 textarea,用 p 來代替,給 p 設定 contenteditable 屬性,同步 textarea 的資料之類。

都太複雜,我隱約覺得開頭那一段程式碼就能解決問題。

經過反覆除錯,我意外寫下如下測試程式碼,竟完美解決問題:

let codePath = document.getElementById('codePath');

codePath.addEventListener('input', function () {
    let _this = this;
    _this.style.height = 'auto';
    _this.style.height = `${_this.scrollHeight}px`;
})

這是為什麼呢,經過除錯,發現如下現象:

// 除錯程式碼
let codePath = document.getElementById('codePath');

codePath.addEventListener('input', function () {
    let _this = this;
    console.log(_this.scrollHeight)
    _this.style.height = `${_this.scrollHeight}px`;
})

用如上除錯程式碼測試,當 textarea 的內容從1行增加到6行,再刪除至1行時,console 輸出如下:
在這裡插入圖片描述
沒錯,內容行增加時,scrollHeight 是正常隨之改變的,但是在內容行減少時,scrollHeight 不會再改變了,會繼續保持最大值。

經觀察和思索,這行程式碼有貓膩 :

_this.style.height = `${_this.scrollHeight}px`;

當內容行增加到6行時,相當於給 textarea 設定了一個120px的固定高度,因為設定了固定高度,當內容行減少時, textarea 不會被繼續撐開,scrollHeight 不會再改變,height 就保持原有值。

可做個簡單測試,給 textarea 設定一個固定高度,比如 200px,當你在這個 textarea 裡從1行內容輸入到6行內容,再刪除至1行內容, textarea 的 scrollHeight 沒有任何變化,因為內容沒有超出 textarea 的區域,不會出現滾動條,scrollHeight 值就不會變化。

既然是固定高度引起的原因,解決的思路就清晰了,給 textarea 設定 height 前,手動去除其原有高度即可,當被去除了高度, textarea 無論有幾行內容,都會出現滾動條,其實際內容高度(也就是scrollHeight)就能獲取到正確的值,再將其值付給 height ,即可完美實現自適應。

所以,如下程式碼中_this.style.height = 'auto';的 auto ,改成 0 或者“1px”也行,只要數值小於一行內容行的高度,能去除原有高度就行。

let codePath = document.getElementById('codePath');

codePath.addEventListener('input', function () {
    let _this = this;
    _this.style.height = 'auto';
    _this.style.height = `${_this.scrollHeight}px`;
})

一句話日記:知其然,知其所以然,那些高手,一定是人碼合一

相關文章