小程序textarea覆盖一个弹窗解决方案

前言

在小程序 textarea 组件上展示一个模态弹窗组件,会发现 textarea 中输入的文字内容,会直接穿透模态弹窗显示在最上面,而且还能点击输入文字。

限制

小程序 textarea 是由客户端创建的原生组件,由于原生组件脱离在 WebView 渲染流程外,因此在使用时有以下限制:

  • 原生组件的层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法盖在原生组件上。

    • 后插入的原生组件可以覆盖之前的原生组件。

  • 原生组件还无法在 picker-view 中使用。

    • 基础库 2.4.4 以下版本,原生组件不支持在 scroll-view、swiper、movable-view 中使用。

  • 部分CSS样式无法应用于原生组件,例如:

    • 无法对原生组件设置 CSS 动画
    • 无法定义原生组件为 position: fixed
    • 不能在父级节点使用 overflow: hidden 来裁剪原生组件的显示区域

  • 原生组件的事件监听不能使用 bind:eventname 的写法,只支持 bindeventname。原生组件也不支持 catch 和 capture 的事件绑定方式。
  • 原生组件会遮挡 vConsole 弹出的调试面板。 在工具上,原生组件是用web组件模拟的,因此很多情况并不能很好的还原真机的表现,建议开发者在使用到原生组件时尽量在真机上进行调试。

那么要在 textarea 上正常的覆盖一个弹窗,该如何做呢?

解决方案

方法一:cover-view 和 cover-image

为了解决原生组件层级最高的限制。小程序专门提供了 cover-view 和 cover-image 组件,可以覆盖在部分原生组件上面。这两个组件也是原生组件,但是使用限制与其他原生组件有所不同。cover-view 只支持嵌套 cover-view、cover-image、button、navigator、ad 等组件,其余组件在真机上都会被忽略。所以如果弹窗中要显示 input、radio、checkbox 等组件的话,该方案无法实现,但对于只是展示文本、按钮和图片的话,还是可以满足的。

<textareavalue="{{text}}"></textarea>

<cover-viewclass="modal modal-fixed">

<cover-viewclass="dialog">

弹窗弹窗弹窗弹窗

<button>按钮</button>

</cover-view>

</cover-view>

方案二:弹窗出现时隐藏 textarea

该方案适合弹窗尺寸能够覆盖整个 textarea 或者弹窗的模态层是不透明的,这样即便 textarea 隐藏了,对用户来说无感知,当弹窗消失以后再把 textarea 显示出来。需要注意的是对于带半透明模态层的弹窗,其所在的页面内容最好不要超过屏幕高度,否则页面滚动会让用户知道 textarea 被隐藏了。

<textareawx:if="{{ !showDialog }}"></textarea>

<viewclass="modal modal-fixed"wx:if="{{showDialog }}">

<viewclass="dialog">

弹窗弹窗弹窗弹窗

<button>按钮</button>

</view>

</view>

方案三:弹窗出现时使用 view 替换 textarea

该方案是方案二的优化,能够保证 textarea 的内容仍然展示,但由于原生组件和 WebView 的差异,无法保证 textarea 和 view 组件展示的一致性,尤其是 字体 ,某些 Android 机型 textarea 和 view 的字体展示不一样,即使设置了 Android 的系统字体 font-family: -apple-system-font, "Helvetica Neue", sans-serif;,所以在弹窗出现时,textarea 和 view 切换会有较为明显的闪动,适当调低模态层的透明度可以缓解闪动的视觉影响。

<textareawx:if="{{!showDialog}}"bindinput="changeText"></textarea>

<viewwx:elseclass="shadow-textarea"style="{{shadowTextStyle}}">

<rich-textspace="nbsp"nodes="{{shadowText}}"></rich-text>

</view>

<viewclass="modal modal-fixed"wx:if="{{showDialog}}">

<viewclass="dialog">

弹窗弹窗弹窗弹窗

<button>按钮</button>

</view>

</view>

getShadowText(text, placeholder) {

const placeholderClass = text === '' ? 'placeholder' : '';

// 将换行符转换为wxml可识别的换行元素 <br/>

let shadowText = text === '' ? placeholder : text.replace(/\n/g, '<br/>');

shadowText = `<div class="rich-text ${placeholderClass}">${shadowText}</div>`;

return shadowText;

},

changeText(event) {

consttext = event.detail.value;

this.setData({

text,

shadowText: this.getShadowText(text, this.properties.placeholder),

});

},

方案四:使用 view 模拟 textarea 常态展示

该方案主要在非编辑状态下使用 view 展示,当点击 view 时,生成 textarea 并进入编辑状态。虽然view 和 textarea 切换后仍然是不同字体(Android),但切换时由于会拉起软键盘,几乎忽略了闪动的视觉影响。可是,该方案有个比较难解决的问题就是,进入编辑状态时光标无法定位到用户点击的位置(一般自动聚焦到末尾),需要用户二次点击定位。

<textareawx:if="{{isEdit}}"bindinput="changeText"></textarea>

<viewwx:elseclass="shadow-textarea"style="{{shadowTextStyle}}">

<rich-textspace="nbsp"nodes="{{shadowText}}"></rich-text>

</view>

<viewclass="modal modal-fixed"wx:if="{{showDialog}}">

<viewclass="dialog">

弹窗弹窗弹窗弹窗

<button>按钮</button>

</view>

</view>

方案五:交互设计避免模态弹窗覆盖 textarea

例如固定高度的 textarea 展示在顶部,弹窗展示在底部,或者改为侧边栏呼出弹出层等等替换的交互设计。

以上是 小程序textarea覆盖一个弹窗解决方案 的全部内容, 来源链接: www.h5w3.com/115434.html

回到顶部