摘要:本文描述了一種實(shí)現(xiàn)隨著文本輸入或刪除能自動(dòng)改變高度適應(yīng)文字量的簡單文本編輯框的方法伊磺,效果入下圖(沒有富文本格式焚辅,只有基本的換行浊仆、空格等格式)记焊。主要思路是建立兩個(gè)textarea
元素,隱藏其中一個(gè)瘦穆,隨著文字輸入檢查隱藏的textarea
元素的滾動(dòng)高度纪隙,把這個(gè)高度值賦給顯示的textarea
。
起因
前段時(shí)間做了一個(gè)類ppt
的在線編輯器扛或,當(dāng)然功能比ppt
簡單很多绵咱。其中在插入文字的時(shí)候由于輸入完成之后要有基本的換行,空格之類的格式熙兔,因此用<textarea>
元素是比較合適的悲伶。但是在textarea
元素內(nèi)輸入文字的時(shí)候,如果內(nèi)容比較多住涉,超出元素高度的時(shí)候麸锉,就會(huì)出現(xiàn)滾動(dòng)條,這顯然是不符合一個(gè)類ppt
編輯器對(duì)文字元素的要求的舆声。當(dāng)然簡單一點(diǎn)可以讓不去管它花沉,提供一個(gè)功能讓用戶自己去調(diào)整文字框的大小,不過既然做了總想做好一點(diǎn)媳握。于是通過搜索和摸索實(shí)現(xiàn)了一個(gè)能夠隨著文字輸入或刪除碱屁,高度能夠自適應(yīng)改變的文本框。
實(shí)現(xiàn)思路和過程
初始方案
一開始的基本思路就是每當(dāng)在textarea元素的內(nèi)容發(fā)生改變之后蛾找,獲取textarea
的scrollHeight
娩脾,然后讓textarea
的style.height
等于這個(gè)值。于是初版代碼大約是這樣(我用的vue
框架打毛,其他框架或者不用框架應(yīng)該也是類似):
<textarea type="text" @focus="textFocus" v-model="content" ref="input" :style="{height: teaxtAreaHeight}" rows="1"
style="overflow-y: hidden;">
</textarea>
export default {
data() {
content: '',
teaxtAreaHeight: ''
},
methods: {
textFocus() {
document.addEventListener('keyup', () => {
this.$nextTick(() => {
const height = `${(this.$refs.input).scrollHeight}px`;
if (height !== this.teaxtAreaHeight) {
this.teaxtAreaHeight = height;
}
});
});
}
}
}
界面上的textarea
元素內(nèi)容綁定了content
變量晦雨,元素高度height
綁定變量textAreaHeight
架曹,初始是默認(rèn)高度。overflow-y
屬性是hidden
闹瞧,為的是不出現(xiàn)滾動(dòng)條。當(dāng)文本框獲得焦點(diǎn)時(shí)展辞,執(zhí)行textFocus
奥邮,監(jiān)聽鍵盤輸入事件,獲取文本框的scrollHeight
也就是滾動(dòng)高度罗珍,如果滾動(dòng)高度和現(xiàn)在文本框的高度不一樣洽腺,說明因?yàn)槲淖州斎雽?dǎo)致了文本內(nèi)容高度與文本框高度不同,則改變文本框高度teaxtAreaHeight
覆旱。其中$nextTick
方法是vue
中用于等待下一次dom
重新渲染后再執(zhí)行其中的代碼蘸朋,因?yàn)槲淖州斎牒笪谋究虻?code>scrollHeight要等到dom
重新渲染才會(huì)變化。這樣就可以實(shí)現(xiàn)隨著文字輸入扣唱,文本框高度自動(dòng)適應(yīng)文本內(nèi)容高度藕坯,不會(huì)有滾動(dòng)條了。
初始方案的問題
上面這個(gè)方案雖然實(shí)現(xiàn)了隨著文字輸入高度自動(dòng)增加來適應(yīng)文本內(nèi)容噪沙,但是有個(gè)問題炼彪,就是不能夠隨著文字的刪除來自動(dòng)減小高度適應(yīng)刪減后的文本高度。因?yàn)橐坏┙otextarea
設(shè)置了較大的高度height
正歼,那么在文字刪除后scollHeight
也不會(huì)重新減小了辐马!
改進(jìn)
為了解決上面的問題,加入第二個(gè)textarea
局义。這個(gè)textarea
始終是隱藏的喜爷,與顯示的textarea
綁定了同樣的文本內(nèi)容,不改變?cè)?code>textarea的height
萄唇,這樣scollHeight
就會(huì)隨著文字內(nèi)容高度的變化而變化檩帐,這樣由它作為一把高度的尺子,以它的scollHeight
為標(biāo)準(zhǔn)去改變顯示textarea
的height
:
<textarea @focus="textFocus" type="text" v-model="content" ref="input" :style="{height: teaxtAreaHeight}"
rows="1" style="overflow-y: hidden;">
</textarea>
<textarea style="position: absolute; visibility:hidden;" ref="heightRuler" v-model="content" rows="1"></textarea>
export default {
data() {
content: '',
teaxtAreaHeight: ''
},
methods: {
textFocus() {
document.addEventListener('keyup', () => {
this.$nextTick(() => {
const height = `${(this.$refs.heightRuler).scrollHeight}px`;
if (height !== this.teaxtAreaHeight) {
this.teaxtAreaHeight = height;
}
});
});
}
}
}
vue優(yōu)化版
思路還是之前那個(gè)思路穷绵,不過代碼可以變得更加優(yōu)雅轿塔。之前的做法是監(jiān)聽鍵盤事件,在vue中還可以直接通過watch監(jiān)聽value值來計(jì)算高度仲墨,也可以通過計(jì)算屬性的set方法在value發(fā)生改變的時(shí)候計(jì)算高度