設計初衷
在開發頁面時,往往需要實現,點擊頁面的導航菜單頁面滾動到相應位置,滾動頁面實現菜單選項的高亮。在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類似于 CSS 的選擇器,但僅支持下列語法。
屬性 | 類型 | 說明 |
---|---|---|
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節點的下邊界坐標widthnumber節點的寬度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', addNum: 0 }, { name: '.panel2', attr: 'panel2_top', addNum: 0 }, { name: '.panel3', attr: 'panel3_top', addNum: 0 }, { name: '.panel4', attr: 'panel4_top', addNum: 0 }, ] 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 hTop = parseInt(e.scrollTop) // 自動切換菜單 let tab=0 if (hTop >= (this.data['panel4_top'] - this.data.menu_top)) { tab=3 } 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.js
// 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', attr: 'menu_top', addNum: 0 }, { name: '.panel1', attr: 'panel1_top', addNum: 0 }, { name: '.panel2', attr: 'panel2_top', addNum: 0 }, { name: '.panel3', attr: 'panel3_top', addNum: 0 }, { name: '.panel4', attr: 'panel4_top', addNum: 0 }, ] 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, }) let arr = ['panel1_top', 'panel2_top', 'panel3_top', '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; }
到此這篇關于微信小程序-自定義菜單導航(實現樓梯效果)的文章就介紹到這了,更多相關微信小程序自定義菜單導航內容請搜索以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持!