1. 程式人生 > >微信小程式開發筆記5——元素隨著頁面滾動吸附在頂部的效果

微信小程式開發筆記5——元素隨著頁面滾動吸附在頂部的效果

現在很多app都有這樣的效果,某元素隨著頁面的滾動,吸附在頂部的效果。本文將介紹實現這種效果的兩種不同的方法。
先看一下效果圖:
sticky

使用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

這種方法分兩步:

  1. 獲取tab最開始距離頂部的位置(或者tab上面元素的總高度,一個意思)。兩種方式都可以,第二種在註釋中。
  2. 頁面滾動時,進行距離的判斷
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()
     */
  }
})

github

demo地址:https://github.com/JerryYuanJ/mini-app-pratice