微信小程序图片组件<image>出现“白线”

705 阅读2分钟

场景复现

水平排列的<image>组件的空白缝隙问题,在部分手机上显示有缝隙,实际上 wxss 设置的是没有任何空间的,并且排查过并非display: inline-block; 而导致的问题。

image.png

而不一定所有的手机上都有缝隙,可能是 DeviceA 上面看起来有缝隙;DeviceB 上面完美衔接。

原因

1)先说结论:

height 出现小数而导致的,如 height: 200.87px;

2)为什么会有小数?

通过检查元素得出结论是 <image mode="widthFix"> 的时候,宽度100%,高度根据图片的宽度保持比例不变情况下自适应(自动计算高度),而计算的时候为了保持图片等比,就出现了高度有小数的情况。

3)更深入的理解

打个比方:一个设备的宽度为375px ,那么在这个设备上渲染一张 750 * 320 图片。

那么这张图片宽度 100% ,并且高度是等比缩放的时候,我们可以通过一个公式来得到这张图片的「实际渲染大小」,(750 / 2 = 375) * (320 / 2 = 160) = 375px * 160px。此时高度的最终计算结果没有小数,因此不会出现“白线”。如果再假设图片高度为 321 的时候,那么 321 / 2 = 160.5 ,这时候“白线”就来了。

其他人的解决方式

有用 display: flex; + flex-direction: column; 或者是 margin-top: -1px; ,发现这对我都不好使,治标不治本。

我目前尝试过可行的方案

封装一个 ImageBase 的基础组件,使用这个基础组件来代替原生 image 组件的渲染。

其原理是,依赖 image 组件的 load 事件来获取关于图片的基础信息,重新计算图片的高度,并且确保高度为整数。

一共四个文件:

// ImageBase.js
Component({
  properties: {
    src: {
      type: String,
      value: ''
    }
  },
  data: {
    height: 'auto'
  },
  methods: {
    imageLoaded(e) {
      const { width, height } = e.detail
      const ratio = width / height

      setTimeout(() => {
        const query = this.createSelectorQuery()
        const selector = `#imageBase`
        query
          .select(selector)
          .boundingClientRect((rect) => {
            const h = (Math.round(rect.width) / ratio) * 2
            this.setData({ height: h + 'rpx' })
          })
          .exec()
      })
    }
  },
  lifetimes: {
    attached() {},
    ready() {}
  }
})


ImageBase.wxml

<image src="{{src}}" id="imageBase" bindload="imageLoaded" style="height: {{height}};" class="image"
  show-menu-by-longpress="true"></image>

ImageBase.less

.image {
  width: 100%;
  display: block;
  font-size: 0;
}

ImageBase.json

{
  "component": true
}