⼩程序-⾃定义菜单导航(实现楼梯效果)
设计初衷
在开发页⾯时,往往需要实现,点击页⾯的导航菜单页⾯滚动到相应位置,滚动页⾯实现菜单选项的⾼亮。在html开发中,我们可以⽤到a 标签锚点实现,jq的动画相结合实现类似效果。在框架中vant UI框架也为我们实现了这⼀效果。
⼩程序该如何实现??
效果展⽰
1. 当菜单导航滚动到页⾯顶部时,菜单吸顶
2. 当点击菜单按钮时,切换到对应区域(过渡到该区域,有动画效果)
3. 当内容区滚动到某类区域时,对应区域的菜单按钮⾼亮
设计思路
1、吸顶效果的实现
获取菜单导航距离页⾯顶部距离wx.createSelectorQuery()
页⾯滚动监听
滚动距离与菜单初始位置值⽐较
1) 距离
const query = wx.createSelectorQuery()
query.select('.menu_nav').boundingClientRect(function(res) {
let obj = {}
if (res && p) {
obj[item.attr] = p)
}
}).exec()
①wx.createSelectorQuery()
返回⼀个 SelectorQuery 对象实例。在⾃定义组件或包含⾃定义组件的页⾯中,应使⽤ ateSelectorQuery() 来代替。
②SelectorQuery.select(string selector)
在当前页⾯下选择第⼀个匹配选择器 selector 的节点。返回⼀个 NodesRef 对象实例,可以⽤于获取节点信息。
selector 语法
selector类似于 CSS 的选择器,但仅⽀持下列语法。
ID选择器:#the-id
class选择器(可以连续指定多个):.a-class.another-class
⼦元素选择器:.the-parent > .the-child
后代选择器:.the-ancestor .the-descendant
跨⾃定义组件的后代选择器:.the-ancestor >>> .the-descendant
多选择器的并集:#a-node, .some-other-nodes
③NodesRef.boundingClientRect(function callback)
添加节点的布局位置的查询请求。相对于显⽰区域,以像素为单位。其功能类似于 DOM 的 getBoundingClientRect。返回
NodesRef 对应的 SelectorQuery。
属性类型说明
id string节点的 ID
dataset Object节点的 dataset
left number节点的左边界坐标
right number节点的右边界坐标
top number节点的上边界坐标
bottom number节点的下边界坐标
width number节点的宽度
height number节点的⾼度
④(function callback)
执⾏所有的请求。请求结果按请求次序构成数组,在callback的第⼀个参数中返回。
2) 页⾯滚动监听
data中初始化--tabFixed=false(表⽰是否固定定位)
滚动条滚动距离超过了菜单初始距离时,tabFixed=true开启定位
// 监听页⾯滚动
onPageScroll: function(e) {
let hTop = parseInt(e.scrollTop)
/
/ 菜单是否需要定位到顶部
if (hTop > u_top) {
this.setData({
tabFixed: true
})
} else {
this.setData({
tabFixed: false
})
}
}
onPageScroll(Object object))
监听⽤户滑动页⾯事件。
参数 Object object:
属性类型说明
scrollTop Number页⾯在垂直⽅向已滚动的距离(单位px)
注意:请只在需要的时候才在 page 中定义此⽅法,不要定义空⽅法。以减少不必要的事件派发对渲染层-逻辑层通信的影响。注意:请避免在 onPageScroll 中过于频繁的执⾏ setData 等引起逻辑层-渲染层通信的操作。尤其是每次传输⼤量数据,会影响通信耗时。
2、切换到对应区域
1. 记录当前点击的菜单并⾼亮
2. 获取每个区域初始距离页⾯顶部距离
3. 设置当前页⾯滚动条滚动到的位置,设置过度时间
// 导航栏切换设置
setSelectType(event) {
let index = event.pe
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 number300否滚动动画的时长,单位 ms
selector string⽆否选择器 2.7.3
success function⽆否接⼝调⽤成功的回调函数
fail function⽆否接⼝调⽤失败的回调函数
complete unction⽆否接⼝调⽤结束的回调函数(调⽤成功、失败都会执⾏)
3) 滚动到某类区域时,对应区域的菜单按钮⾼亮
1. 获取初始时区域距离顶端距离
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) => {
let obj = {}
if (res && p) {
obj[item.attr] = p)
if (item.addNum) {
obj[item.attr] += item.addNum
}
that.setData({
...obj
})
}
}).exec()
})
2. 滚动监听是否超过了该区域
// 监听页⾯滚动
onPageScroll: function(e) {
let hTop = parseInt(e.scrollTop)
// ⾃动切换菜单
let tab=0
if (hTop >= (this.data['panel4_top'] - u_top)) {
tab=3
}else if (hTop >= (this.data['panel3_top'] - u_top)){ tab=2
}
else if (hTop >= (this.data['panel2_top'] - u_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,
js导航栏下拉菜单panel2_top: 0,
panel3_top: 0,
panel4_top: 0,
},
/**
* ⽣命周期函数--监听页⾯加载
*/
onLoad: function (options) {
},
onShow:function (options){
},
/
/ 获取距离页⾯顶部⾼度
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) => {
if (res && p) {
obj[item.attr] = p)
if (item.addNum) {
obj[item.attr] += item.addNum
}
that.setData({
...obj
})
}
}).exec()
})
},
// 导航栏切换设置
setSelectType(event) {
let index = event.pe
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 > u_top) {
this.setData({
tabFixed: true
})
} else {
this.setData({
tabFixed: false
})
}
// ⾃动切换菜单
if (hTop >= (this.data['panel4_top'] - u_top)) {
this.setData({
tabIndex: 3,
})
}else if (hTop >= (this.data['panel3_top'] - u_top)){
this.setData({
tabIndex: 2,
})
}
else if (hTop >= (this.data['panel2_top'] - u_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;
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论