小程序轮播图的高度如何与图片高度保持一致

625 阅读2分钟

“我正在参加「掘金·启航计划」”

一、存在现象

  • 在原生小程序中,我们从服务器获取轮播图的数据,这些图片的数据都是有一定宽高的,我们需要去适配这些图片在不同手机上显示时的宽高,不然的话,在不同的设备上就会不同的效果,也就出现了所谓的bug,如下案例:

  • 这是在iPhone Xr上的显示效果:轮播图的指示点显示正常 image.png

  • 这是在iPhone 5上的显示效果:轮播图的指示点就到图片下方去了 image.png

二、解决方法

思路

  • 在图片加载完成后,获取到图片的高度,获取到之后进行赋值。这样的话,我们需要使用image标签的bindload属性,当图片加载完成时触发

image.png

  • 获取图片高度,可以当做获取这个轮播图组件的高度,这组件是小程序界面上的一个节点,可以使用获取界面上的节点信息APIwx.createSelectorQuery()来获取
const query = wx.createSelectorQuery()
query.select('#the-id').boundingClientRect()
query.selectViewport().scrollOffset()
query.exec(function(res){
  res[0].top       // #the-id节点的上边界坐标
  res[1].scrollTop // 显示区域的竖直滚动位置
})
  • 节点信息查询 API 可以用于获取节点属性、样式、在界面上的位置等信息。最常见的用法是使用这个接口来查询某个节点的当前位置,以及界面的滚动位置。如下图所示,里面有我们所需要的height,我们将这个height赋值给swiper组件,再令image标签mode="widthFix",即可自动适应轮播图高度和图片的高度保持一致

    • widthFix:缩放模式,宽度不变,高度自动变化,保持原图宽高比不变
    • HeightFix:缩放模式,高度不变,宽度自动变化,保持原图宽高比不变
  • 这是iPhone Xr上的数据,height:152.4375 image.png

  • 这是iPhone 5上的数据,height:118.21875 image.png

实现

  • wxml:轮播图
<swiper class="swiper" autoplay indicator-dots circular interval="{{4000}}" style="height: {{swiperHeight}}px;">
  <block wx:for="{{banners}}" wx:key="bannerId">
    <swiper-item class="swiper-item">
      <image class="swiper-image" src="{{item.pic}}" mode="widthFix" bindload="getSwiperImageLoaded"></image>
    </swiper-item>
  </block>
</swiper>
  • js:只展示获取图片高度的代码,像获取轮播图数据代码已省略
Page({
  data: {
    swiperHeight: 0, // 轮播图组件初始高度
  },
  
  // 图片加载完成
  getSwiperImageLoaded() {
    // 获取图片高度
    const query = wx.createSelectorQuery();
    query.select(".swiper-image").boundingClientRect();
    query.exec((res) => {
      this.setData({ swiperHeight: rect.height });
    });
  },
})
  • 在上述代码中getSwiperImageLoaded方法也可以进行抽离到utils中成为一个工具函数,并用Promise进行返回,方便其他地方需要使用到
export default function (selector) {
  return new Promise((resolve) => {
    const query = wx.createSelectorQuery();
    query.select(selector).boundingClientRect();
    query.exec(resolve)
  });
}
  • 所以在上述的实现代码中getSwiperImageLoaded方法可以进行如下的优化:
getSwiperImageLoaded() {
    // 优化
    queryRect(".swiper-image").then((res) => {
      const rect = res[0];
      this.setData({ swiperHeight: rect.height });
    });
  },
  • 如此一来,在iPhone 5上的轮播图组件展示也正常

image.png

  • 最后,因为获取的是轮播图,那么获取的数据就不止一条,按以上代码逻辑,获取到多少条数据就会执行多少遍setData赋值操作,所以可以考虑使用防抖或者节流进行进一步优化。