今天测试小程序时,发现在公司两部iPhoneX上出现了不符合预期的效果,最后发现是在低版本iOS中,微信小程序的底层框架对aspect-radio的支持存在问题

异常展示

在拖拽画面中的圆圈时,会调用微信的catch:touchstartcatch:touchmovecatch:touchend 三个接口,动态计算圆圈的位置和两侧直线的长度,再加上一个throttle函数,限制其调用频率,以防影响低配置手机的体验。

最初的解决方案是固定圆圈的宽度为父节点的8%,再用aspect-ratio调整他的高度。

.circle-dragger {
  content: "";
  position: absolute;
  transform-origin: 50% 50%;
  transform: translateY(-50%) translateX(-50%);
  width: 8%;
  aspect-ratio: 1 / 1;
  border-radius: 50%;

但是在这个情况中,圆圈的高度却跟着手指的拖动发生了高度的变化,所以自然而然就怀疑上了这个aspect-ratio。


针对这个问题,解决方案有三种:

方案一 将%百分比换算成vw,然后用vw表示高度

.circle-dragger {
  content: "";
  position: absolute;
  transform-origin: 50% 50%;
  transform: translateY(-50%) translateX(-50%);
  width: 5.6vw;
  height: 5.6vw;
  border-radius: 50%;

这个方案可以解决这个问题,但是无法在不确定相对屏幕宽度的情况下使用

方案二 使用padding-top伪元素trick

.circle-dragger {
  content: "";
  position: absolute;
  transform-origin: 50% 50%;
  transform: translateY(-50%) translateX(-50%);
  width: 8%;
  border-radius: 50%;
}
.circle-dragger::before {
  content: "";
  width: 1px;
  margin-left: -1px;
  float: left;
  height: 0;
  padding-top: 100%;
}
.circle-dragger::after
  content: "";
  display: table;
  clear: both;
}

这个方法同样可以用来防止aspect-ratio的元素内容超出限定的比例问题。通过before伪元素给circle-dragger设定了一个会浮动变化的高度,再由after伪元素消除浮动,就产生了一个可以伸缩的aspect-ratio替代方案。

方案三 使用JS动态计算高度

由于微信小程序渲染层和逻辑层分由两个线程管理,为减少线程通信产生的性能损失,小程序一直都是推荐减少使用setData,避免将不需要渲染层处理的数据在代码中频繁更新。所以这个方案在微信小程序中不是一个高效的方案。

最终效果

By samuel