分享微信小程序中實現sticky效果的(de)列表頁
發表時(shí)間:2022-9-14
發布人(rén):融晨科技
浏覽次數:217
首先什麽是(shì)sticky效果呢
具體參照餓了(le/liǎo)麽APP的(de)商品列表頁(小程序版本發現并未實現)
具體的(de)效果及實現可以(yǐ)查看一下這(zhè)個(gè)demo => sticky demo on codepen
簡單地(dì / de)說(shuō)就(jiù)是(shì)标題會有粘黏的(de)效果,向下滑動時(shí)跟着列表走,向上(shàng)滑動到(dào)頂部時(shí)将會固定在(zài)頂部。
但是(shì)如果在(zài)不(bù)考慮兼容性的(de)情況下(IOS6以(yǐ)上(shàng)、 Safari9.1+、 chrome56+)
其實從CSS3開始有一個(gè)position屬性sticky就(jiù)能實現這(zhè)種效果
{
position: sticky;
top: 0;
}
隻需要(yào / yāo)這(zhè)兩行就(jiù)能實現,然而(ér)...然而(ér)兼容性那是(shì)相當的(de)差,那麽好用的(de)一個(gè)屬性爲(wéi / wèi)什麽兼容性那麽差呢?
那麽餓了(le/liǎo)麽的(de)商品列表頁在(zài)小程序中實有哪些步驟呢?
- 利用scroll-view裏的(de)scroll-into-view屬性,具體可查看小程序的(de)文檔
- 實現sticky效果(可參照 codepen 的(de) demo)
- 獲取每個(gè)scroll-into-view的(de)scrollTop
- 監聽scroll的(de)滾動,并改變scroll-into-view
下來(lái)來(lái)讓我們看一下具體該如何實現
<scroll-view scroll-y class="left-wrapper" id="left">
<view wx:for="..." bindtap="..."></view>
<!--這(zhè)裏是(shì)左側的(de)類型選擇-->
</scroll-view>
<scroll-view scroll-y
class="right-wrapper"
bindscroll="onScroll"
scroll-into-view="{{toView}}"
id="right">
<view wx:for="{{items}}" wx-for-item="item" class="lists" id="{{item.title}}">
<view class="type-title" style="{{style}}">
<!-- 這(zhè)個(gè)就(jiù)是(shì)ticky header部分 -->
{{item.title}}
</view>
<view class="content">
<view wx:for="{{item.child}}" class="item">
<!--這(zhè)裏是(shì)需要(yào / yāo)展示具體的(de)列表項-->
</view>
</view>
</view>
</scroll-view>
左側列表頁沒什麽好講的(de),無非就(jiù)是(shì)按下某個(gè)類型,給上(shàng)一個(gè)checked樣式,然後改變toView(關鍵)的(de)值。
那麽toView是(shì)什麽呢?toView的(de)值是(shì)和(hé / huò)scroll-view裏面你需要(yào / yāo)跳轉的(de)view的(de)id對應起來(lái)的(de),也(yě)就(jiù)是(shì)代碼中的(de)這(zhè)個(gè)id
<view wx:for="{{items}}" wx-for-item="item" class="lists" id="{{item.title}}">
所以(yǐ)當左側按下對應的(de)按鈕以(yǐ)後,右側的(de)scroll就(jiù)會跳轉到(dào)相應id的(de)scroll-into-view裏面,
其實到(dào)目前爲(wéi / wèi)止已經實現了(le/liǎo)sticky header + 跳轉的(de)問題了(le/liǎo)
但是(shì)...
如果滑動右側的(de)滾動條的(de)話,左側的(de)數據如何跟着變化呢?
假如不(bù)是(shì)小程序的(de)話應該很多人(rén)都知道(dào)怎麽做,無非就(jiù)是(shì)監聽滾動條,判斷滾動條的(de)位置,然後根據區域去改變左側的(de)選擇。
但是(shì)...
小程序如果獲得scroll-into-view在(zài)scroll-view裏面的(de)位置呢???
小程序是(shì)沒有類似document.getElementById()這(zhè)種Dom操作的(de)
也(yě)沒法使用JQuery的(de)$去快捷地(dì / de)獲取scrollTop的(de)
也(yě)不(bù)能像vue一樣直接操作$el的(de)
還好小程序在(zài)1.4時(shí)開放了(le/liǎo)一個(gè)接口wx.createSelectorQuery()
wx.createSelectorQuery()
返回一個(gè)SelectorQuery對象實例。可以(yǐ)在(zài)這(zhè)個(gè)實例上(shàng)使用select等方法選擇節點,并使用boundingClientRect等方法選擇需要(yào / yāo)查詢的(de)信息。
nodesRef.boundingClientRect([callback])
添加節點的(de)布局位置的(de)查詢請求,相對于(yú)顯示區域,以(yǐ)像素爲(wéi / wèi)單位。其功能類似于(yú)DOM的(de)getBoundingClientRect。返回值是(shì)nodesRef對應的(de)selectorQuery。
返回的(de)節點信息中,每個(gè)節點的(de)位置用left、right、top、bottom、width、height字段描述。如果提供了(le/liǎo)callback回調函數,在(zài)執行selectQuery的(de)exec方法後,節點信息會在(zài)callback中返回。
然後可以(yǐ)通過這(zhè)個(gè)方法拿到(dào)所有的(de)scroll-into-view的(de)位置
let query = wepy.createSelectorQuery()
for (let i = 0; i < this.types.length; ++i) {
let id = this.types[i]
query.select(`#${id}`).boundingClientRect((rect) => {
this.scrollTops[id] = rect.top
}).exec()
}
特别注意
這(zhè)個(gè)操作必須得放在(zài)onReady ()的(de)時(shí)候去做,否則将無法得到(dào)rect屬性
得到(dào)這(zhè)個(gè)屬性以(yǐ)後其實就(jiù)很好操作了(le/liǎo),直接上(shàng)代碼了(le/liǎo)
onScroll (event) {
// 如果是(shì)右側的(de)滾動view
if (event.currentTarget.id === 'right') {
// 判斷滾動的(de)方向
let top = event.detail.scrollTop
this.dir = this.currentTop < top ? 'down' : 'up'
this.currentTop = top
// 判斷當前滾動條所在(zài)區域,如果不(bù)在(zài)當前區域則進行跳轉
if (top > this.scrollTops[this.getNextView()] &&
this.dir === 'down' &&
this.checked < this.types.length - 1) {
this.setChecked(this.checked + 1)
}
if (top < this.scrollTops[this.toView] &&
this.dir === 'up' &&
this.checked > 0) {
this.setChecked(this.checked - 1)
}
}
}
然後一個(gè)簡單的(de)具有sticky效果的(de)商品列表頁跳轉功能就(jiù)實現了(le/liǎo)。
坑
- scroll-view必須設置高度,否則在(zài)IOS上(shàng)将無法使用scroll-into-view跳轉
- 使用createSelectorQuery必須在(zài)頁面渲染完成以(yǐ)後
存在(zài)問題
- scroll會有個(gè)慣性運動,這(zhè)時(shí)候按左側的(de)按鈕切換scroll-into-view會和(hé / huò)onScroll事件發生一些沖突,測試IOS存在(zài)有該問題,希望大(dà)神給予些指導意見。
說(shuō)明
由于(yú)采用了(le/liǎo)wepy構建的(de)小程序,所以(yǐ)在(zài)部分代碼上(shàng)會和(hé / huò)小程序有出(chū)入(改過一些),主要(yào / yāo)是(shì)思路。
順便丢個(gè)wepy的(de)github
wepy的(de)本意是(shì)希望小程序能像vue一樣開發,由于(yú)本人(rén)一直在(zài)用vue做項目,所以(yǐ)用wepy開發小程序會順手一些,但是(shì)wepy雖然盡力貼合vue,但在(zài)某些設計上(shàng)存在(zài)着一定的(de)問題,但相對來(lái)說(shuō)比直接開發小程序用起來(lái)舒服一些。