微信小程式開發筆記5——元素隨著頁面滾動吸附在頂部的效果
阿新 • • 發佈:2018-11-04
現在很多app都有這樣的效果,某元素隨著頁面的滾動,吸附在頂部的效果。本文將介紹實現這種效果的兩種不同的方法。
先看一下效果圖:
使用IntersectionObserver
思路
上一篇部落格詳細介紹了IntersectionObserver的用法。這裡用來實現這種吸附的效果,應該先想到的是,判斷哪兩個元素的相交。你可以根據需要來選擇不同參照物。當相交的時候,將元素置頂吸附;不相交的時候,回到原來的位置。
實現
wxml
我將該頁面分成了三部分。最上面是幻燈片,接著是的標籤卡元件,最後是一個很長的內容區,因為要保證頁面可以向下滾動的。
<view class="slider">
<swiper class='slider-items' indicator-dots="{{true}}"
indicator-color="white" interval="{{true}}">
<block wx:for="{{[1,2,3]}}" wx:key="*this">
<swiper-item>
<view class='slider-item item-{{index}}'></view>
</swiper-item >
</block>
</swiper>
</view>
<view class='{{tabFixed ? "fixed-tab" : ""}}'>
<view class='tab'>
<tabbar tabItems="{{tabOptions}}">
</tabbar>
</view>
</view>
<view class='content'></view>
wxss
這裡要定義吸附的效果(fixed在頂部,即樣式中的.fixed-tab)。
.slider{
position: relative;
}
.slider-items{
height: 260rpx;
}
.slider-item {
width: 100%;
height: 100%;
}
.item-0{
background-color: lightblue;
}
.item-1{
background-color: lightgreen;
}
.item-2{
background-color: lightpink;
}
.tab{
background-color: white;
}
.fixed-tab{
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 99;
}
.content{
height: 1500px;
background-color: #eaeaea;
width: 100%;
}
js
在initTabObserver
方法中可以看到,使用的參照物件是頁面,觀察的是slider。當兩者相交時(即slider在頁面上能看到時),tab該在哪在哪;當不相交時(頁面上看不到slider),就把tab置頂吸附。通過tabFixed
來控制樣式從而控制這種置頂吸附的效果。
Page({
data: {
tabFixed: false,
tabOptions: ['全部', '附近', '特別關注']
},
/**
* 初始化觀察器
*/
initTabObserver() {
this.tabObserver = wx.createIntersectionObserver(this)
this.tabObserver
// 相對於頁面可視區
.relativeToViewport()
// 相對於某一個元素
.observe('.slider', (res) => {
console.info(res)
const visible = res.intersectionRatio > 0
this.setData({ tabFixed: !visible })
})
},
onLoad(){
this.initTabObserver()
},
onUnload(){
this.tabObserver.disconnect()
}
})
我們也可以指定一個元素作為參照物,但是要注意,這個參照物,不能於我們的觀察物件是相對靜止的,即兩者不以相同的速度相同的方向同時運動,否則永遠也不會相交。我們可以對上面的程式碼做些改動:
在wxml中新增一個fixed的參照元素:
<view class='fixed-position'></view>
在wxss新增對應樣式:
.fixed-position{
width: 100%;
height: 1px;
position: fixed;
visibility: hidden;
}
改寫js中的initTabObserver方法:
initTabObserver() {
this.tabObserver = wx.createIntersectionObserver(this)
this.tabObserver
.relativeTo('.fixed-position')
.observe('.slider', (res) => {
console.info(res)
const visible = res.intersectionRatio > 0
this.setData({ tabFixed: !visible })
})
},
一樣可以達到同樣的效果。
注意要在頁面解除安裝的時候
disconnect
掉這個觀察者,以免造成不必要的資源浪費。
使用onPageScroll
思路
這種方法就相對好理解一點了,也應該是常用的做法。就是在頁面的滾動監聽回撥中,判斷我們要吸附的元素距離頂部的距離x
與頁面滾動距離y
的大小。如果x > y
,即還沒有滾動到要吸附的元素的位置,保持原樣;否則即切換樣式,置頂吸附。
實現
wxml
<view class="placeholder-content flex-center">佔位的一個div</view>
<view class='{{tabFixed ? "fixed-tab" : ""}}'>
<view class='tab'>
<tabbar tabItems="{{tabOptions}}">
</tabbar>
</view>
</view>
<view class='content'></view>
wxss
.container{
height: 1000px;
width: 100%;
}
.placeholder-content{
height: 400rpx;
width: 100%;
background-color: green;
color: white;
}
.tab{
background-color: white;
}
.fixed-tab{
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 99;
}
.content{
height: 800px;
background-color: lightgray;
}
js
這種方法分兩步:
- 獲取tab最開始距離頂部的位置(或者tab上面元素的總高度,一個意思)。兩種方式都可以,第二種在註釋中。
- 頁面滾動時,進行距離的判斷
Page({
data: {
tabFixed: false,
tabOptions: ['全部', '附近', '特別關注'],
placeholderHeight: null
},
onPageScroll(e){
// 頁面滾動的距離
const scrollDistance = e.scrollTop
// 佔位元素的高度
const placeholderHeight = this.data.placeholderHeight
this.setData({
tabFixed: scrollDistance > placeholderHeight
})
},
onReady(){
const query = wx.createSelectorQuery()
const self = this
// 這裡:獲取placeholder的height = tab的top(頂部座標)
// 在你明確tab上面有A什麼的時候,可以直接獲取A的高度: example1
// 否則,必須獲取tab的top值: example2
// example1
query.select(".placeholder-content").boundingClientRect(function (res) {
self.setData({
placeholderHeight: res.height
})
}).exec()
// example2
/**
* query.select(".tab").boundingClientRect(function (res) {
console.info(res)
self.setData({
placeholderHeight: res.top
})
}).exec()
*/
}
})