Vue中textarea自適應(yīng)高度方案的實(shí)現(xiàn)
先給方案,Vue棧有需求的同學(xué)可以直接下載vue-awesome-textarea
隱藏的問(wèn)題
拋開原生JS,框架的大部分UI庫(kù)都支持自適應(yīng)textarea高度功能,但普遍都忽略了一個(gè)功能,就是自適應(yīng)高度的回顯。
使用這些庫(kù)的時(shí)候,我們很容易的在textarea中鍵入內(nèi)容,超出范圍時(shí)會(huì)自動(dòng)延展一行,保證內(nèi)容高度的自適應(yīng)。當(dāng)我們提交內(nèi)容,在其它頁(yè)面使用同樣的UI來(lái)渲染時(shí),麻煩的就來(lái)了,有些UI庫(kù)是不支持自適應(yīng)回顯的,這就需要我們通過(guò)行高、行數(shù)甚至高度之間的計(jì)算得出一個(gè)基值,從而實(shí)現(xiàn)回顯。
解決自適應(yīng)高度的方案
常見得方案有兩種,一種是在頁(yè)面地“邊遠(yuǎn)地區(qū)”添加一個(gè)ghost dom來(lái)模擬輸入換行,這個(gè)dom的可能是editable屬性為true的div或者是一個(gè)一摸一樣得textarea。
以element-ui的input組件舉例,當(dāng)我們?cè)诮M件內(nèi)輸入值時(shí),會(huì)調(diào)用resizeTextarea方法
resizeTextarea() { ? if (this.$isServer) return; ? const { autosize, type } = this; ? if (type !== 'textarea') return; ? if (!autosize) { ? ? this.textareaCalcStyle = { ? ? ? minHeight: calcTextareaHeight(this.$refs.textarea).minHeight ? ? }; ? ? return; ? } ? const minRows = autosize.minRows; ? const maxRows = autosize.maxRows; ? this.textareaCalcStyle = calcTextareaHeight(this.$refs.textarea, minRows, maxRows); }
當(dāng)設(shè)置了autosize為true則textarea設(shè)為自適應(yīng)高度。此時(shí)textarea的高度會(huì)通過(guò)calcTextareaHeight方法實(shí)時(shí)計(jì)算。
export default function calcTextareaHeight( ? targetElement, ? minRows = 1, ? maxRows = null ) { ? if (!hiddenTextarea) { ? ? hiddenTextarea = document.createElement('textarea'); ? ? document.body.appendChild(hiddenTextarea); ? } ? let { ? ? paddingSize, ? ? borderSize, ? ? boxSizing, ? ? contextStyle ? } = calculateNodeStyling(targetElement); ? hiddenTextarea.setAttribute('style', `${contextStyle};${HIDDEN_STYLE}`); ? hiddenTextarea.value = targetElement.value || targetElement.placeholder || ''; ? let height = hiddenTextarea.scrollHeight; ? const result = {}; ? if (boxSizing === 'border-box') { ? ? height = height + borderSize; ? } else if (boxSizing === 'content-box') { ? ? height = height - paddingSize; ? } ? hiddenTextarea.value = ''; ? let singleRowHeight = hiddenTextarea.scrollHeight - paddingSize; ? if (minRows !== null) { ? ? let minHeight = singleRowHeight * minRows; ? ? if (boxSizing === 'border-box') { ? ? ? minHeight = minHeight + paddingSize + borderSize; ? ? } ? ? height = Math.max(minHeight, height); ? ? result.minHeight = `${ minHeight }px`; ? } ? if (maxRows !== null) { ? ? let maxHeight = singleRowHeight * maxRows; ? ? if (boxSizing === 'border-box') { ? ? ? maxHeight = maxHeight + paddingSize + borderSize; ? ? } ? ? height = Math.min(maxHeight, height); ? } ? result.height = `${ height }px`; ? hiddenTextarea.parentNode && hiddenTextarea.parentNode.removeChild(hiddenTextarea); ? hiddenTextarea = null; ? return result; };
我們可以看到
if (!hiddenTextarea) { hiddenTextarea = document.createElement('textarea'); document.body.appendChild(hiddenTextarea); }
element-ui創(chuàng)建了一個(gè)textarea的dom,通過(guò)calculateNodeStyling方法將真正的textarea的樣式復(fù)制給hiddenTextarea(overflow不同步,真正的textarea是為hidden)。接著監(jiān)聽textarea的輸入值,同步給hiddenTextarea。同時(shí)將hiddenTextarea的scrollHeight同步給textarea的高度,最后再將dom銷毀掉。
關(guān)于樣式的同步,element這里用了getComputedStyle和getPropertyValue這兩個(gè)API。當(dāng)然,如果你自己封裝的話,也可以使用css預(yù)處理器的mixin。
第二種方案與第一種方案類似,不過(guò)不會(huì)創(chuàng)建額外的dom。以開頭的vue-awesome-textarea舉例:
init() { this.initAutoResize() }, initAutoResize () { this.autoResize && this.$nextTick(this.calcResize) }
在頁(yè)面mounted或者內(nèi)容變動(dòng)且開啟自適應(yīng)高度autoResize的時(shí)候,執(zhí)行this.calcResize方法。
calcResize() { ? this.resetHeight() ? this.calcTextareaH() }, resetHeight() { ? this.height = 'auto' }, calcTextareaH() { ? let contentHeight = this.calcContentHeight() ? this.height = this.calcHeightChange(contentHeight) + 'px' ? if (this.needUpdateRows(contentHeight)) { ? ? this.updateRows(contentHeight) ? } ? this.oldContentHeight = contentHeight }, calcContentHeight () { ? const { paddingSize } = this.calcNodeStyle(this.$el) ? return this.$el.scrollHeight - paddingSize },
resetHeight()是來(lái)初始化textarea的高度,默認(rèn)為auto。calcTextareaH()方法是用來(lái)計(jì)算內(nèi)容區(qū)域的高度(textarea的scrollHeight減去padding的高度),同時(shí)將計(jì)算好的高度實(shí)時(shí)同步給textarea的高:
this.height = this.calcHeightChange(contentHeight) + 'px'
相比方案一,這個(gè)方案采用的思路相同(動(dòng)態(tài)修改高度),但是減少了額外的dom創(chuàng)建和銷毀的過(guò)程。
此外,vue-awesome-textarea還支持在自適應(yīng)的過(guò)程中回調(diào)行數(shù),可以更好的支持?jǐn)?shù)據(jù)回顯。實(shí)現(xiàn)的方法也很簡(jiǎn)單:
computed: { ? ... ? oneRowsHeight() { ? ? return this.calcContentHeight() / Number(this.rows) || 0 ? } ? ... }
在computed中我們計(jì)算出單行的高度,同時(shí)在執(zhí)行this.calcTextareaH()方法時(shí)我們記錄下內(nèi)容高度:
this.oldContentHeight = contentHeight
接著我們會(huì)比對(duì)是否存在添加行操作,一旦添加則新的內(nèi)容高度和老的內(nèi)容高度會(huì)不同:
needUpdateRows(newContentHeight) { return this.oldContentHeight !== newContentHeight },
此時(shí)我們會(huì)把最新的行高emit到組件外部:
updateRows(contentHeight) { this.$emit('getRows', Math.round(contentHeight / this.oneRowsHeight)) }
到此這篇關(guān)于Vue中textarea自適應(yīng)高度方案的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Vue textarea自適應(yīng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue+echarts動(dòng)態(tài)更新數(shù)據(jù)及數(shù)據(jù)變化重新渲染方式
這篇文章主要介紹了vue+echarts動(dòng)態(tài)更新數(shù)據(jù)及數(shù)據(jù)變化重新渲染方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06重新認(rèn)識(shí)vue之事件阻止冒泡的實(shí)現(xiàn)
這篇文章主要介紹了重新認(rèn)識(shí)vue之事件阻止冒泡的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08vue.js學(xué)習(xí)筆記之綁定style樣式和class列表
數(shù)據(jù)綁定一個(gè)常見需求是操作元素的 class 列表和它的內(nèi)聯(lián)樣式。這篇文章主要介紹了vue.js綁定style和class的相關(guān)資料,需要的朋友可以參考下2016-10-10詳解Vue3?SFC?和?TSX?方式調(diào)用子組件中的函數(shù)
在使用?.vue?定義的組件中,setup?中提供了?defineExpose()?方法,該方法可以將組件內(nèi)部的方法暴露給父組件,這篇文章主要介紹了Vue3?SFC?和?TSX?方式調(diào)用子組件中的函數(shù),需要的朋友可以參考下2022-10-10vue使用JSEncrypt對(duì)密碼本地存儲(chǔ)時(shí)加解密的實(shí)現(xiàn)
本文主要介紹了vue使用JSEncrypt對(duì)密碼本地存儲(chǔ)時(shí)加解密,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07Vue全局事件總線$bus安裝與應(yīng)用小結(jié)
這篇文章主要介紹了Vue全局事件總線$bus安裝與應(yīng)用,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09