小程序 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

前端娛樂圈發展這麼快,感受小程序可能會跟不上潮流。

最後

給我正在開發的小程序預熱一下~

歡迎關注~

相關文章
相關標籤/搜索