最近作的一個小程序需求,其中一個頁面使用到了 textarea
這個小程序組件,而後點擊頁面上的某個元素,會觸發頁面彈起一個彈窗,這時發現 textarea
的 placeholder
文字或者輸入的文字內容,會直接穿透遮罩層和浮動彈窗,顯示在最上面,開始時我覺得是遮罩層和浮動彈窗的層級捨得小了,因而改大,誰知道沒用,改到了 99999
也沒用,因而我意識到這應該不是我代碼的問題,網上一搜,果真有故事。css
textarea
這是最簡單的解決手段,通常彈窗的時候,都會帶個遮罩層,把遮罩層下面的內容隱藏一部分,用戶基本上不會注意的,而後再去掉彈窗和遮罩層的時候再把 textarea
顯示出來。 這種方法簡單有效,大部分狀況下均可以這麼解決。html
<textarea wx:if="{{ showMask }}"></textarea>
複製代碼
有時候, textarea
穿透的不是遮罩層,或者遮罩層以一種半透明而非徹底遮住頁面內容的形式呈現,擔憂用戶可以看到由於 textarea
的消失而致使頁面跳動,產生很差的用戶體驗,那麼就可使用替代元素來替代 textarea
而非將之直接隱藏掉。node
基本的 textarea
組件只接受文本的輸入,拋開可輸入性的話,外觀上看就是一個含有文本節點的簡單元素,只須要獲取當前狀態下的 textarea
中輸入的文字,將之賦予給一個樣式與 textarea
相同的普通元素,就達到了臨時替代的效果。小程序
<!-- 這是真正的 textarea組件 -->
<textarea id="text-area" value="{{txtRealContent}}" bindinput='txtInput' wx:if="{{!showMask}}" />
<!-- 這是用於模擬 textarea的替代元素 -->
<view class='rich-text' style="{{('height:' + txtHeight + 'px')}}" wx:else>
<rich-text nodes="{{txtRealContent}}"></rich-text>
</view>
複製代碼
如上所示緩存
textarea
中已經輸入的內容,因此給 textarea
元素加了個 bindinput
的監聽器showMask
用於標識是否顯示遮罩層(或者其餘可能會被 textarea穿透的浮動元素),若是顯示遮罩層,則隱藏 textarea
元素,並顯示替代原宿textarea
的隱藏使用了 wx:if
,會使其完全地從頁面中消失,而從新顯示出來的時候,textarea
元素會從新建立,丟失原先輸入,因此給其加了個 value
屬性,其值 txtRealContent
就是緩存的 textarea
已經輸入的文本內容;若是你不用這種方法,不讓 textarea
徹底顯示,而僅僅是隱藏,例如使用 hidden="{{ showMask ? true :false }}"
,由於不涉及到 textarea
的刪除與重建,因此就無需添加 value
屬性來控制文本內容了。textarea
是能夠輸入可換行的文本內容的,因此這裏使用了 rich-text
組件,在使用的時候,我發現 rich-text
好像不支持溢出隱藏,因此又額外在其外面包了一層 view
組件,並將其高度設置爲和 textarea
相同上面四個步驟,都比較簡單,稍微須要注意的是,若是 textarea
的內容包含了換行文本,則須要對換行符進行處理:xss
textareaContent.replace(/\n/g, '<br/>')
複製代碼
若是你想讓 textarea
自動增長高度而不是固定高度,給 textarea
加了個 auto-height
,那麼就須要「實時」獲取其高度 說是 「實時」,其實也並非那麼實時,不考慮其餘樣式的變化, textarea
的高度與行數有關,每增減一行,其高度纔會變化,因此只須要監控其內容行數的變化便可,剛好 textarea
組件也已經提供了這個監控器:bindlinechange
。ui
原理說完了,完整實例代碼以下:this
index.wxmlspa
<view class="page-body">
<button bindtap="changeMaskVisible">切換mask</button>
<view class="textarea-wrp">
<textarea id="text-area" value="{{txtContent}}" bindinput='txtInput' bindlinechange="textAreaLineChange" wx:if="{{!showMask}}" auto-height />
<view class='rich-text' style="{{('height:' + txtHeight + 'px')}}" wx:else>
<rich-text nodes="{{txtRealContent}}"></rich-text>
</view>
</view>
<button>Footer</button>
<view wx:if="{{showMask}}" bindtap="changeMaskVisible" class="mask">
<view class="mask-content"></view>
</view>
</view>
複製代碼
index.jscode
Page({
data: {
txtRealContent: '',
txtContent: '',
showMask: false,
txtHeight: 0
},
textAreaLineChange(e) {
this.setData({ txtHeight: e.detail.height })
},
txtInput(e) {
this.setData({ txtContent: e.detail.value })
},
changeMaskVisible(e) {
if (!this.data.showMask) {
// 將換行符轉換爲wxml可識別的換行元素 <br/>
const txtRealContent = this.data.txtContent.replace(/\n/g, '<br/>')
this.setData({ txtRealContent })
}
this.setData({ showMask: !this.data.showMask })
}
})
複製代碼
index.wxss
.rich-text {
overflow: hidden;
}
.mask {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, .6);
z-index: 10;
}
.mask-content {
position: fixed;
top: 44%;
left: 50%;
height: 60%;
width: 60%;
transform: translate(-50%, -50%);
background-color: yellowgreen;
z-index: 12;
}
複製代碼