小程序 swiper 如何多页面高度自适应

轮播,这个概念只要作过 UI 的都不会陌生,盲猜市场上 90% 的应用都有这个需求,在 iOS 和 Android 上都有很完善的控件,好比 Android 的 ViewPager 和 iOS 的 UIScrollview。前端

小程序这么牛逼,确定也要有控件支持这个特性啊, swiper 就这么诞生了。小程序

可是 swiper 有一个很严重的问题,就是高度默认 150px,且不能够自适应内容调整高度。markdown

这就有问题了,我如今有一个多 Tab 的页面,最少高度要满屏,还要超出内容能够往下滚动,此时就蒙蔽了,怎么给 swiper 设置高度呢?xss

首先看一下我搜索到的一些方法:this

  1. 在初始化的时候获取到屏幕的高度,而后将高度设置到 swiper 上,至于滚动的问题,在里面再嵌入一个 scroll-viewspa

    这个问题有不少坑,首先 屏幕的高度要比内容区的高度大,这么设置之后就算内容较少,页面也能滑动一点;其次,小程序的 scroll-view 在实现上拉加载更多的时候,坑更多。设计

  2. 每一个 item 的高度都一致,根据 item 的数量和统一的高度计算出内容的高度,而后设置进去code

    这个方案感受彻底是 zz 方案,局限性太大了orm

个人方案

一句话解释:给 swiper-item 内部添加三个锚点,最上面一个,最下面一个,还有一个锚点始终位于屏幕最底下。根据这三个锚点计算出内容高度和内容显示区高度。 PS:锚点,宽高为 0 的不可见的 view,用于获取定位xml

若是还有不理解能够看下面这个示意图:

这三个锚点的具体做用是用来计算 swiper 内容高度和 swiper 距离屏幕底部的具体,计算方式以下:

  1. 使用 swiper-item 内部的两个锚点计算出内容区高度
  2. 经过屏幕底部和 swiper-item 顶部的锚点计算出离屏幕底部的距离

接下来看看代码具体实现

代码实现

page.wxml

<view>
	<swiper style="height: {{anchor.deviceHeight + 'px'}}">
		<swiper-item>
			<view class="anchor-top"></view>
			<!-- 你的内容 -->
			<view class="anchor-bottom"></view>
		</swiper-item>
	</swiper>
	<view class="anchor-screen-bottom"></view>
</view>
复制代码

page.wxss

.anchor-top {
    width: 0;
    height: 0;
}

.anchor-bottom {
    width: 0;
    height: 0;
}

.anchor-screen-bottom {
    position: absolute;
    bottom: 0;
    width: 0;
    height: 0;
}
复制代码

page.js

Page({
	data: {
		anchor: {
			deviceHeight: 0,
      anchorTop: 0,
      anchorBottom: 0,
      anchorScreenBottom: 0
		}
	},
	onReady: function() {
		this.computeSwiperHeight(0)
	},
	computeSwiperHeight(pageIndex) {
	  let getSwiperHeight = () => {
      let min = this.data.anchor.anchorScreenBottom - this.data.anchor.anchorTop;
      let value = this.data.anchor.anchorBottom - this.data.anchor.anchorTop
      return Math.max(min, value)
	  }
	  wx.createSelectorQuery()
      .select('.anchor-screen-bottom')
      .boundingClientRect()
      .selectViewport()
      .scrollOffset()
      .exec(res => {
        this.data.anchor.anchorScreenBottom = res[0].bottom
      })
	  wx.createSelectorQuery()
      .selectAll('.anchor-top')
      .boundingClientRect()
      .selectViewport()
      .scrollOffset()
      .exec(res => {
        this.data.anchor.anchorTop = res[0].top
        this.setData({
          'anchor.deviceHeight': getSwiperHeight()
        })
      })
	  wx.createSelectorQuery()
      .selectAll('.anchor-bottom')
      .boundingClientRect()
      .selectViewport()
      .scrollOffset()
      .exec(res => {
        this.data.anchor.anchorBottom = res[0].bottom
        this.setData({
          'anchor.deviceHeight': getSwiperHeight()
        })
      })
	},
})
复制代码

适配多页面

固然,确定要适配每一个页面的高度不同的状况。方案也很简单,屏幕底部的锚只须要一个了,给每一个 swiper-item 的都添加两个锚点,和以前同样一个在上面一个在下面,在切换页面的时候,根据当前页面的锚点从新计算一下高度,而后设置进去。

只须要在原有基础上改一下代码:

page.wxml

<view>
	<swiper style="height: {{anchor.deviceHeight + 'px'}}" bindchange="swiperChange">
		<swiper-item>
			<view class="anchor-top"></view>
			<!-- 你的内容 -->
			<view class="anchor-bottom"></view>
		</swiper-item>
		<swiper-item>
			<view class="anchor-top"></view>
			<!-- 你的内容 -->
			<view class="anchor-bottom"></view>
		</swiper-item>
	</swiper>
	<view class="anchor-screen-bottom"></view>
</view>
复制代码

page.wxss

CSS 不须要改动

page.js

Page({
	data: {
		anchor: {
			deviceHeight: 0,
      anchorTop: 0,
      anchorBottom: 0,
      anchorScreenBottom: 0
		}
	},
	onReady: function() {
		this.computeSwiperHeight(0)
	},
	swiperChange(e) {
    this.computeSwiperHeight(e.detail.current)
  },
	computeSwiperHeight(pageIndex) {
	  let getSwiperHeight = () => {
      let min = this.data.anchor.anchorScreenBottom - this.data.anchor.anchorTop;
      let value = this.data.anchor.anchorBottom - this.data.anchor.anchorTop
      return Math.max(min, value)
	  }
	  wx.createSelectorQuery()
      .select('.anchor-screen-bottom')
      .boundingClientRect()
      .selectViewport()
      .scrollOffset()
      .exec(res => {
        this.data.anchor.anchorScreenBottom = res[0].bottom
      })
	  wx.createSelectorQuery()
      .selectAll('.anchor-top')
      .boundingClientRect()
      .selectViewport()
      .scrollOffset()
      .exec(res => {
        this.data.anchor.anchorTop = res[0][pageIndex].top
        this.setData({
          'anchor.deviceHeight': getSwiperHeight()
        })
      })
	  wx.createSelectorQuery()
      .selectAll('.anchor-bottom')
      .boundingClientRect()
      .selectViewport()
      .scrollOffset()
      .exec(res => {
        this.data.anchor.anchorBottom = res[0][pageIndex].bottom
        this.setData({
          'anchor.deviceHeight': getSwiperHeight()
        })
      })
	},
})
复制代码

实现效果

  1. swiper 的高度高度根据内容自适应
  2. swiper 的高度最小占满屏幕,最大和内容同样高(为了用户滑动体验(若是划页后高度忽然变小,用户在原来的位置就划不回去了)
  3. 适配不一样高度的页面

这个方案是了实现为本身的需求而写的,应该不适应所有的场景,不过但愿能够为你提供一点思路。

感想

小程序里的坑真的不少,并且有些 API 设计的很奇怪,真的不知道当初开发人员怀着怎样的心路历程设计出的 API。

我的感受小程序就是给前端新造了一个轮子,更新还很不及时,有不少陈年老 Bug,好比本文讲的 swiper

前端娱乐圈发展这么快,感受小程序可能会跟不上潮流。

最后

给我正在开发的小程序预热一下~

欢迎关注~

相关文章
相关标签/搜索