亲宝软件园·资讯

展开

微信小程序自定义菜单导航

久宇诗 人气:0

设计初衷

在开发页面时,往往需要实现,点击页面的导航菜单页面滚动到相应位置,滚动页面实现菜单选项的高亮。在html开发中,我们可以用到a标签锚点实现,jq的动画相结合实现类似效果。在框架中vant UI框架也为我们实现了这一效果。

微信小程序该如何实现??

效果展示

设计思路

1、吸顶效果的实现

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) 页面滚动监听

// 监听页面滚动
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;
}

加载全部内容

相关教程
猜你喜欢
用户评论