微信小程式自定義選單導航實現樓梯效果
設計初衷
在開發頁面時,往往需要實現,點選頁面的導航選單頁面滾動到相應位置,滾動頁面實現選單選項的高亮。在html開發中,我們可以用到a標籤錨點實現,jq的動畫相結合實現類似效果。在框架中vant UI框架也為我們實現了這一效果。
微信小程式該如何實現??
效果展示
- 當選單導航滾動到頁面頂部時,選單吸頂
- 當點選選單按鈕時,切換到對應區域(過渡到該區域,有動畫效果)
- 當內容區滾動到某類區域時,對應區域的選單按鈕高亮
設計思路
1、吸頂效果的實現
- 獲取選單導航距離頁面頂部距離
wx.createSelectorQuery()
- 頁面滾動監聽
- 滾動距離與選單初始位置值比較
1) 距離
const query = wx.createSelectorQuery() query.select('.menu_nav').boundingClientRect(function(res) { let obj = {} if (res && res.top) { obj[item.attr] = parseInt(res.top) } }).exec()
①wx.createSelectorQuery()
返回一個 SelectorQuery 物件例項。在自定義元件或包含自定義元件的頁面中,應使用 this.createSelectorQuery() 來代替。②SelectorQuery.select(string selector)
在當前頁面下選擇第一個匹配選擇器 selector 的節點。返回一個 NodesRef 物件例項,可以用於獲取節點資訊。
selector 語法
selector類似於 的選擇器,但僅支援下列語法。
屬性 | 型別 | 說明 |
---|---|---|
id | string | 節點的 ID |
dataset | Object | 節點的 dataset |
left | number | 節點的左邊界座標 |
right | number | 節點的右邊界座標 |
top | number | 節點的上邊界座標 |
bottom | number | 節點的下邊界座標 |
width | number | 節點的寬度 |
height | number | 節點的高度 |
③NodesRef.boundingClientRect(function callback)
新增節點的佈局位置的查詢請求。相對於顯示區域,以畫素為單位。其功能類似於 DOM 的 getBoundingClientRect。返回 NodesRef 對應的 SelectorQuery。
屬性型別說明idstring節點的 IDdatasetObject節點的 datasetleftnumber節點的左邊界座標rightnumber節點的右邊界座標topnumber節點的上邊界座標bottomnumber節點的下邊界座標widtheAuAUknumber節點的寬度heightnumber節點的高度
④SelectorQuery.exec(function callback)
執行所有的請求。請求結果按請求次序構成陣列,在callback的第一個引數中返回。
2) 頁面滾動監聽
- data中初始化--
tabFixed=false
(表示是否固定定位) - 滾動條滾動距離超過了選單初始距離時,
tabFixed=true
開啟定位
// 監聽頁面滾動 onPageScroll: function(e) { let hTop = parseInt(e.scrollTop) // 選單是否需要定位到頂部 if (hTop > this.data.menu_top) { this.setData({ tabFixed: true }) } else { this.setData({ tabFixed: false }) } }
onPageScroll(Object object))
監聽使用者滑動頁面事件。
引數 Object object:
屬性 | 型別 | 說明 |
---|---|---|
scrollTop | Number | 頁面在垂直方向已滾動的距離(單位px) |
注意:請只在需要的時候才在 page 中定義此方法,不要定義空方法。以減少不必要的事件派發對渲染層-邏輯層通訊的影響。 注意:請避免在 onPageScroll 中過於頻繁的執行 setData 等引起邏輯層-渲染層通訊的操作。尤其是每次傳輸大量資料,會影響通訊耗時。
2、切換到對應區域
- 記錄當前點選的選單並高亮
- 獲取每個區域初始距離頁面頂部距離
- 設定當前頁面滾動條滾動到的位置,設定過度時間
// 導航欄切換設定 setSelectType(event) { let index = event.currentTarget.dataset.type this.setData({ tabIndex: index,}) let arr = ['panel1_top','panel2_top','panel3_top','panel4_top'] let _this = this wx.pageScrollTo({ scrollTop: _this.data[arr[index]],duration: 500 }) },
wx.pageScrollTo(Object object)
將頁面滾動到目標位置,支援選擇器和滾動距離兩種方式定位
屬性 | 型別 | 預設值 | 必填 | 說明 |
---|---|---|---|---|
scrollTop | number | 無 | 否 | 滾動到頁面的目標位置,單位 px |
duration | number | 300 | 否 | 滾動動畫的時長,單位 ms |
selector | string | 無 | 否 | 選擇器 2.7.3 |
success | function | 無 | 否 | 介面呼叫成功的回撥函式 |
fail | function | 無 | 否 | 介面呼叫失敗的回撥函式 |
complete | unction | 無 | 否 | 介面呼叫結束的回撥函式(呼叫成功、失敗都會執行) |
3) 滾動到某類區域時,對應區域的選單按鈕高亮
獲取初始時區域距離頂端距離
let arr = [ { name: '.menu-nav',attr: 'menu_top',addNum: 0 },{ name: '.panel1',attr: 'panel1_top',{ name: '.panel2',attr: 'panel2_top',{ name: '.panel3',attr: 'panel3_top',{ name: '.panel4',attr: 'panel4_top',] arr.forEach((item,i) => { wx.createSelectorQuery().select(item.name).boundingClientRect(function(res) { let obj = {} if (res && res.top) { obj[item.attr] = parseInt(res.top) if (item.addNum) { obj[item.attr] += item.addNum } that.setData({ ...obj }) } }).exec() })
滾動監聽是否超過了該區域
// 監聽頁面滾動
onPageScroll: function(e) {
let hThttp://www.cppcns.comop = parseInt(e.scrollTop)
// 自動切換選單
let tab=0
if (hTop >= (this.data['panel4_top'] - this.data.menu_top)) {
tab=3www.cppcns.com
}else if (hTop >= (this.data['panel3_top'] - this.data.menu_top)){
tab=2
}
else if (hTop >= (this.data['panel2_top'] - this.data.menu_top)){
tab=1
}
this.setData({
tabIndex: tab,})
},
完整程式碼
index.
// pages/index/index.js Page({ /** * 頁面的初始資料 */ data: { tabIndex: 0,//當前處於那個選單 menuList: ['選單1','選單2','選單3','選單4'],//導航選單 tabFixed: false,//是否定位 // 初始頁面距離頂部距離 menu_top: 0,panel1_top: 0,panel2_top: 0,panel3_top: 0,panel4_top: 0,},/** * 生命週期函式--監聽頁面載入 */ onLoad: function (options) { },onShow:function (options){ this.getTopDistance() },// 獲取距離頁面頂部高度 getTopDistance() { let that = this let arr = [{ name: '.menu-nav',addNum: 0 },{ name: '.panel1',{ name: '.panel2',{ name: '.panel3',{ name: '.panel4',] arr.forEach((item,i) => { wx.createSelectorQuery().select(item.name).boundingClientRect(function (res) { let obj = {} if (res && res.top) { obj[item.attr] = parseInt(res.top) if (item.addNum) { obj[item.attr] += item.addNum } that.setData({ ...obj }) } }).exec() }) },// 導航欄切換設定 setSelectType(event) { let index = event.currentTarget.dataset.type this.setData({ tabIndex: index,'panel4_top'] let _this = this wx.pageScrollTo({ scrollTop: _this.data[arr[index]],duration: 500 }) },// 監聽頁面滾動 onPageScroll: function (e) { let hTop = parseInt(e.scrollTop) // 選單是否需要定位到頂部 if (hTop > this.data.menu_top) { this.setData({ tabFixed: true }) } else { this.setData({ tabFixed: false }) } // 自動切換選單 if (hTop >= (this.data['panel4_top'] - this.data.menu_top)) { this.setData({ tabIndex: 3,}) }else if (hTop >= (this.data['panel3_top'] - this.data.menu_top)){ this.setData({ tabIndex: 2,}) } else if (hTop >= (this.data['panel2_top'] - this.data.menu_top)){ this.setData({ tabIndex: 1,}) }else{ this.setData({ tabIndex: 0,}) } },})
index.wxml
<view class="Main"> <view class="head"> 我是頭部區域 </view> <view class="{{tabFixed?'is-fixed':''}} menu-nav"> <text wx:for="{{menuList}}" class="{{tabIndex==index?'is-select':''}}" bind:tap="setSelectType" data-type='{{index}}'>{{item}}</text> </view> <view class="content"> <view class="panel1 panel">頁面1</view> <view class="panel2 panel">頁面2</view> <view class="panel3 panel">頁面3</view> <view class="panel4 panel">頁面4</view> </view> </view>
index.wxss
.menu-nav { display: flex; align-items: center; justify-content: space-around; color: black; padding: 10px 0; width: 100%; background-color: white; } .is-select { color: red; } .head { display: flex; align-items: center; justify-content: center; font-size: 40px; height: 120px; background-color: greenyellow; } .is-fixed { position: fixed; top: 0; } .panel { display: flex; align-items: center; justify-content: center; font-size: 20px; } .panel1 { height: 800rpx; background-color: rebeccapurple; } .panel2 { height: 700rpx; background-color: blue; } .panel3 { height: 1000rpx; background-color: orange; } .panel4 { height: 1200rpx; background-color: pink; }
到此這篇關於微信小程式-自定義選單導航(實現樓梯效果)的文章就介紹到這了,更多相關微信小程式自定義選單導航內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!