輪播诱告,這個概念只要做過 UI 的都不會陌生藻雪,盲猜市場上 90% 的應(yīng)用都有這個需求万搔,在 iOS 和 Android 上都有很完善的控件蘸嘶,比如 Android 的 ViewPager 和 iOS 的 UIScrollview。
小程序這么牛逼计雌,肯定也要有控件支持這個特性啊悄晃, swiper
就這么誕生了。
但是 swiper
有一個很嚴(yán)重的問題凿滤,就是高度默認(rèn) 150px妈橄,且不可以自適應(yīng)內(nèi)容調(diào)整高度庶近。
這就有問題了,我現(xiàn)在有一個多 Tab 的頁面眷蚓,最少高度要滿屏鼻种,還要超出內(nèi)容可以往下滾動,此時就蒙蔽了溪椎,怎么給 swiper
設(shè)置高度呢普舆?
首先看一下我搜索到的一些方法:
-
在初始化的時候獲取到屏幕的高度,然后將高度設(shè)置到
swiper
上校读,至于滾動的問題沼侣,在里面再嵌入一個scroll-view
這個問題有很多坑,首先 屏幕的高度要比內(nèi)容區(qū)的高度大歉秫,這么設(shè)置以后就算內(nèi)容較少蛾洛,頁面也能滑動一點;其次雁芙,小程序的
scroll-view
在實現(xiàn)上拉加載更多的時候轧膘,坑更多。 -
每個 item 的高度都一致兔甘,根據(jù) item 的數(shù)量和統(tǒng)一的高度計算出內(nèi)容的高度谎碍,然后設(shè)置進(jìn)去
這個方案感覺完全是 zz 方案,局限性太大了
我的方案
一句話解釋:給 swiper-item 內(nèi)部添加三個錨點洞焙,最上面一個蟆淀,最下面一個,還有一個錨點始終位于屏幕最底下澡匪。根據(jù)這三個錨點計算出內(nèi)容高度和內(nèi)容顯示區(qū)高度熔任。
PS:錨點,寬高為 0 的不可見的 view唁情,用于獲取定位
如果還有不理解可以看下面這個示意圖:
這三個錨點的具體作用是用來計算 swiper 內(nèi)容高度和 swiper 距離屏幕底部的具體疑苔,計算方式如下:
- 使用
swiper-item
內(nèi)部的兩個錨點計算出內(nèi)容區(qū)高度 - 通過屏幕底部和
swiper-item
頂部的錨點計算出離屏幕底部的距離
接下來看看代碼具體實現(xiàn)
代碼實現(xiàn)
page.wxml
<view>
<swiper style="height: {{anchor.deviceHeight + 'px'}}">
<swiper-item>
<view class="anchor-top"></view>
<!-- 你的內(nèi)容 -->
<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()
})
})
},
})
適配多頁面
當(dāng)然,肯定要適配每個頁面的高度不一樣的情況甸鸟。方案也很簡單惦费,屏幕底部的錨只需要一個了,給每個 swiper-item 的都添加兩個錨點抢韭,和之前一樣一個在上面一個在下面薪贫,在切換頁面的時候,根據(jù)當(dāng)前頁面的錨點重新計算一下高度篮绰,然后設(shè)置進(jìn)去后雷。
只需要在原有基礎(chǔ)上改一下代碼:
page.wxml
<view>
<swiper style="height: {{anchor.deviceHeight + 'px'}}" bindchange="swiperChange">
<swiper-item>
<view class="anchor-top"></view>
<!-- 你的內(nèi)容 -->
<view class="anchor-bottom"></view>
</swiper-item>
<swiper-item>
<view class="anchor-top"></view>
<!-- 你的內(nèi)容 -->
<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()
})
})
},
})
實現(xiàn)效果
-
swiper
的高度高度根據(jù)內(nèi)容自適應(yīng) -
swiper
的高度最小占滿屏幕季惯,最大和內(nèi)容一樣高(為了用戶滑動體驗(如果劃頁后高度突然變小吠各,用戶在原來的位置就劃不回去了) - 適配不同高度的頁面
這個方案是了實現(xiàn)為自己的需求而寫的臀突,應(yīng)該不適應(yīng)全部的場景,不過希望可以為你提供一點思路贾漏。
感想
小程序里的坑真的很多候学,而且有些 API 設(shè)計的很奇怪,真的不知道當(dāng)初開發(fā)人員懷著怎樣的心路歷程設(shè)計出的 API纵散。
個人感覺小程序就是給前端新造了一個輪子梳码,更新還很不及時,有很多陳年老 Bug伍掀,比如本文講的 swiper
掰茶。
前端娛樂圈發(fā)展這么快,感覺小程序可能會跟不上潮流蜜笤。
最后
給我正在開發(fā)的小程序預(yù)熱一下~
歡迎關(guān)注~