设计初衷在开发页面时,往往需要实现,点击页面的导航菜单页面滚动到相应位置,滚动页面实现菜单选项的高亮。在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.jsPage({ /** * 页面的初始数据 */ 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;} 到此这篇关于微信小程序-自定义菜单导航(实现楼梯效果)的文章就介绍到这了,更多相关微信小程序自定义菜单导航内容请搜索51zixue.net以前的文章或继续浏览下面的相关文章希望大家以后多多支持51zixue.net! 下载地址: vue JavaScript |