最近作的一个小程序需求,其中一个页面使用到了 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;
}
复制代码