阅读 619

微信小程序cover-view踩坑之旅

1. 为什么要写这篇文章

鄙人有幸参与迭代版本中小程序接入原生直播的业务开发工作,在项目迭代过程中,遇见过许多“百思不得其解”的问题。

由于直播需要使用live-player,而live-player是微信原生组件,也就是层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法盖在原生组件上,所以小程序专门提供了cover-viewcover-image组件,可以覆盖在部分原生组件上面,在适配cover-view的时候也是遇到了很多事情(坑?)

2. 基础介绍

1. 底层默认属性

cover-view {
  display: block;
  line-height: 1.2;
  overflow: hidden;
  white-space: nowrap;
  pointer-events: auto;
  font-family: -apple-system;
}
复制代码

2. 介绍

覆盖在原生组件之上的文本视图。
可覆盖的原生组件包括 mapvideocanvascameralive-playerlive-pusher
只支持嵌套 cover-viewcover-image,可在 cover-view 中使用 button

3. Bug & Tip

image.png

3. 遇到的相关问题及解决办法

1. 字体被截断、显示不全问题(仅在iOS下会出现)

原因:iOS上计算宽高的问题

<cover-view class="row">
  <cover-view class="btn">打开弹窗</cover-view>
</cover-view>
复制代码
.row {
  display: flex;
  align-items: center;
  .btn {
+   padding: 0 20rpx;
    color: #fff;
    background-color: red;
  }
}
复制代码

显示效果如下:                                加了padding以后
image.png  image.png
解决办法:
在「打开弹窗」的文字后加入固定宽度的一个cover-view即可,也就是把父节点的宽度撑开。

<cover-view class="row">
  <cover-view class="btn">打开弹窗<cover-view class="space" /></cover-view>
</cover-view>
复制代码
.row {
  display: flex;
  align-items: center;
  .btn {
    padding: 0 20rpx;
    color: #fff;
    background-color: red;
  }
}

+ .space {
+   display: inline-block;
+   width: 2rpx;
+   line-height: 1;
+ }
复制代码

最终显示效果:
image.png

2. 嵌套cover-view时,自定义组件slot及父节点不支持wx:if进行隐藏和显示,否则不显示

<!-- page -->
<page-container id="container">
  <cover-view class="page">
    <cover-view class="row">
      <cover-view class="btn" catch:tap="openModal"
        >打开弹窗<cover-view class="space"
      /></cover-view>
    </cover-view>
  </cover-view>
  <modal visible="{{ visible }}" bind:on-close="closeModal">
    <cover-view>我是弹窗的</cover-view>
  </modal>
</page-container>

<!-- modal -->
<cover-view class="modal" wx:if="{{ visible }}">
  <cover-view class="mask" catch:tap="closeModal"></cover-view>
  <cover-view class="content">
    <slot></slot>
  </cover-view>
</cover-view>
复制代码
// modal
.modal {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

.mask {
  width: 100%;
  height: 100%;
  background-color: rgba($color: #000, $alpha: 0.4);
}

.content {
  position: absolute;
  top: 50%;
  left: 50%;
  background-color: #fff;
  transform: translate(-50%, -50%);
}
复制代码

导致如下问题:
打开弹窗时,弹窗内部显示的slot不展示,当点击遮罩进行关闭弹窗时,会出现,弹窗关闭后,slot中的文字显示,然后消失。
image.pngimage.png
所以只能将 wx:if 改为用css去控制 modal 的展示和隐藏,即使用display: block 和 display: none;

<cover-view class="modal {{ visible ? 'show' : '' }}">
  <cover-view class="mask" catch:tap="closeModal"></cover-view>
  <cover-view class="content">
    <slot></slot>
  </cover-view>
</cover-view>
复制代码
.modal {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
+ display: none;
}

.mask {
  width: 100%;
  height: 100%;
  background-color: rgba($color: #000, $alpha: 0.4);
}

.content {
  position: absolute;
  top: 50%;
  left: 50%;
  background-color: #fff;
  transform: translate(-50%, -50%);
}

+ .show {
+   display: block;
+ }
复制代码

3. 在cover-view中使用button

<cover-view class="action-contain action-button-class" bindtap="handleCloseAction">
  <button open-type="share" class="action-item" bindtap="handleClickShare" data-type="action">
    分享给朋友
  </button>
  <cover-view class="action-item" bindtap="handleGenerateImage">
    生成分享图
  </cover-view>
</cover-view>
复制代码

button在编译的时候,会自动在button下加入两层的cover-view,并会赋予一些自己的样式。
image.png

4. cover-image使用border-radius无效

如果想对cover-image使用border-radius,需要在cover-image外包一层cover-view,对cover-view进行使用border-radius,并且将cover-view设置overflow: hidden。
举个🌰

<cover-view
  class="external-class cover-avatar"
  style="height:{{ size }}{{ unit }};width:{{ size }}{{ unit }};{{ radius !== -1 ? 'border-radius:' + radius + unit + ';' : '' }};{{ externalStyle }}"
  bindtap="onClick"
>
  <cover-view
    class="cover-avatar-container"
    style="{{ radius !== -1 ? 'border-radius:' + radius + unit + ';' : '' }}"
  >
    <cover-image class="cover-avatar-image" src="{{ src }}" />
  </cover-view>
</cover-view>
复制代码
.cover-avatar {
  box-sizing: border-box;
  border: 1rpx solid rgba(0, 0, 0, 0.05);
  &-container {
    width: 100%;
    height: 100%;
    overflow: hidden;
  }
}
复制代码

5. cover-view设置overflow: scroll后,touchend事件不触发

<cover-view class="list" catchtouchend="handleTouchEnd">
  <cover-view>
    <cover-view style="display: flex">
      <cover-view style="display: inline-block">
        <cover-view class="item">代码片段是一种可分享的小项目,可用于分享小程序和小游戏的开发经验、展示组件和 API 的使用、复现开发问题等等。分享代码片段会得到一个链接,所有拥有此分享链接的人可以在工具中导入此代码片段。如果网页可点击的链接指向的是分享链接,那么点击链接也会自动打开工具进入代码片段导入页。使用最新版的开发者工具可以</cover-view>
      </cover-view>
    </cover-view>
  </cover-view>
  <cover-view>
    <cover-view style="display: flex">
      <cover-view style="display: inline-block">
        <cover-view class="item">代码片段是一种可分享的小项目,可用于分享小程序和小游戏的开发经验、展示组件和 API 的使用、复现开发问题等等。分享代码片段会得到一个链接,所有拥有此分享链接的人可以在工具中导入此代码片段。如果网页可点击的链接指向的是分享链接,那么点击链接也会自动打开工具进入代码片段导入页。使用最新版的开发者工具可以</cover-view>
      </cover-view>
    </cover-view>
  </cover-view>
</cover-view>
复制代码
.list {
  width: 100%;
  height: 300rpx;
  display: inline-block;
  overflow-y: scroll;
}

.item {
  width: 100%;
  white-space: normal;
}

cover-view {
  line-height: normal;
  overflow: visible;
}
复制代码
const app = getApp()

Page({
  data: {

  },
  handleTouchEnd() {
    console.log('end...')
  }
})
复制代码

当cover-view设置滚动后,touch的相关事件触发会有问题,当未达到scroll的效果时,touch事件生效,当cover-view能进行scroll时,touch不生效,目前还未有解决办法。。。

7. 对cover-view进行wx:if判断

问题:隐藏时,cover-view只是做销毁处理,对性能并无太大影响,而对于显示Dom的时候,需要重新渲染整块的cover-view,对部分旧的手机有很大的性能消耗,会导致显示卡顿,显示类似于未做懒加载的图片一样,四面八方逐个开始渲染,display: block | none 与wx: if大同小异。
解决办法:不做wx:if的判断,对需要隐藏的cover-view不做销毁的处理,可使用css的属性去对dom节点的位置、属性做处理,如:left、opacity,如果在隐藏的dom节点中,有可点击的dom,则不可使用opacity。

4. 总结

涉及到原生组件相关的都需要使用cover-view和cover-image,当然这俩的问题也是比较多的,在进行使用的时候,要去阅读微信开放文档,测试时需用真机去进行测试,用开发者工具去进行开发的话,看上去一切都是没问题的,如果你换到手机上,那可能就会有很多问题了,开发完一个基础模块后,最好用真机去测试一下当前模块的功能是否符合逻辑。

文章分类
前端
文章标签