小程序锚点效果

业务背景:小程序原生中实现类似h5的锚点效果,而且顶部tab可以随着滑动自适应居中

话不多说,上码,粘过去直接用
※※※由于是从项目中摘出来的,所以有些没用上的代码,就没删除

wxml:

<view class="" hover-class="none" hover-stop-propagation="false">
  <view class="navlist cs-fix" id="navlist">
    <scroll-view scroll-x scroll-into-view="{{active_tab}}" scroll-with-animation="true">
      <block wx:for="{{navList}}" wx:key="index" wx:for-item="navitem" wx:for-index="idx">
        <view class="alleverynav _inline " data-idx='{{idx}}' data-name="nav{{navitem.nav_id}}" data-id="{{navitem.nav_id}}" bindtap="navBtn" id="tab_{{idx}}">
          <view class="everynav {{currentCategory==idx?'active':''}}">{{navitem.nav_name}}</view>
          <view wx:if="{{currentCategory==idx}}" class="botline"></view>
        </view>
      </block>
    </scroll-view>
  </view>
  <scroll-view scroll-into-view="{{scrollInTo}}" scroll-y="true" bindscroll="scrolling" style="height: 100vh;" class="{{showNull ? 'scrollbox' : ''}}">
    <block wx:for="{{navList}}" wx:key='index' wx:for-item='itemName'>
      <view id="nav{{itemName.nav_id}}" class="every eve{{index+1}}">这是{{itemName.nav_name}}</view>
    </block>
    <view class="" style="width: 100%;height: 80rpx;"></view>
  </scroll-view>
</view>

js:

Page({
  data: {
    currentCategory: 0,
    moveStartPos: 0,
    active_tab: 'tab_0',
    navList: [{
        nav_name: '不知道咋说',
        nav_id: 0
      },
      {
        nav_name: '准备好了吗',
        nav_id: 1
      },
      {
        nav_name: '来吧',
        nav_id: 2
      },
      {
        nav_name: '开始',
        nav_id: 3
      },
      {
        nav_name: '哎呀',
        nav_id: 4
      },
      {
        nav_name: '出错了',
        nav_id: 5
      },
      {
        nav_name: '算了',
        nav_id: 6
      },

    ],
  },
  onLoad: function (options) {},
  onReady: function() {
    setTimeout(()=>{
      this.tabfn()
    },500)
  },
  navBtn: function (e) {
    let id = e.currentTarget.dataset.id
    let idx = e.currentTarget.dataset.idx;
    this.setData({
      active_tab: 'tab_' + ((idx - 2) < 0 ? 0 : (idx - 1)),
      currentCategory: id,
      scrolly: true,
      scrollTop: this.data.jltop
    }, () => {
      this.setData({
        scrollInTo: e.currentTarget.dataset.name,
      })
    })
    wx.createSelectorQuery().select('#navlist').boundingClientRect((rect) => {
      // 节点的上边界坐标
      let top = rect.top;
      if (top == 0) {
        this.setData({
          showNull: true
        })
      } else {
        this.setData({
          showNull: false
        })
      }
    }).exec()
  },
  scrolling(e) {
    wx.createSelectorQuery().select('#navlist').boundingClientRect((rect) => {
      let top = rect.top;
      if (top == 0) {
        this.setData({
          scrolly: true
        })
      } else {
        this.setData({
          scrolly: false
        })
      }
    }).exec()
    // 将当前的距离传入
    this.onScrollViewScroll({
      scrollTop: e.detail.scrollTop
    })
  },
  onScrollViewScroll(e) {
    // 当前滚动的距离
    let scrollTop = e.scrollTop
    // moveStartPos记录着上一次滚动完成时的位置, 用于判断滚动方向
    // 如果现在的滚动距离大于moveStartPos说明正在往下滚动
    if (scrollTop > this.data.moveStartPos) {
      this.setData({
        moveStartPos: scrollTop
      })
      // 遍历每个商品距离顶部的距离
      this.data.navList.forEach((item, index) => {
        // 如果滚动的距离大于某个商品到顶部的距离说明该商品到了顶部, 减10是为了减少触发距离
        if (Number(scrollTop) > item.top  - 58) {
          // 当前分类的索引小于满足条件的商品索引就赋值, 跳到下一个分类
          if (this.data.currentCategory < index) {
            this.setData({
              currentCategory: index,
              active_tab: 'tab_' + ((index - 2) < 0 ? 0 : (index - 2)),
            })
          }
        }
      })
      // 如果现在的滚动距离小于moveStartPos说明正在往上滚动 
    } else if (scrollTop < this.data.moveStartPos) {

      this.setData({
        moveStartPos: scrollTop
      })
      this.data.navList.forEach((item, index) => {
        if (Number(scrollTop) < item.top - 58) {
          if (this.data.currentCategory >= index) {
            this.setData({
              currentCategory: index ? index - 1 : index,
              active_tab: 'tab_' + ((index - 2) < 0 ? 0 : (index - 2)),
            })
          }
        }
      })
    }
  },
  tabfn: function () {
    this.animation = wx.createAnimation()
    var that = this
    var arr = []
    // 页面准备完成之后获取每个分类距离顶部的高度, 存储在数组productsTop中
    setTimeout(function () {
      var query = wx.createSelectorQuery()
      var toptapArr = that.data.navList;
      toptapArr.forEach((item, index) => {
        query.select('#nav' + item.nav_id).boundingClientRect((res) => {
          if (res) {
            item.top = res.top;
            that.setData({
              navList: toptapArr,
              distanceTop: that.data.navList[0].top
            })
          }
        })
      })
      query.selectAll('.cs-fix').boundingClientRect((rect) => {
        that.categoryTop = rect[0].top
      }).exec()
    }, 800)
  },

})

wxss:

._inline {
  display: inline-block;
}

.navlist .active {
  font-size: 32rpx;
  font-family: PingFangSC-Medium, PingFang SC;
  font-weight: 500;
  color: #333333;
  height: 75rpx;
}

.navlist .botline {
  width: 48rpx;
  height: 4rpx;
  background: #D71C18;
  border-radius: 2rpx;
  margin: 0 auto;
}

.navlist .alleverynav {
  margin-right: 56rpx;

}

.navlist .everynav {
  font-size: 26rpx;
  font-family: PingFangSC-Regular, PingFang SC;
  color: #666666;
}

.navlist {
  white-space: nowrap;
  overflow-x: scroll;
  height: 90rpx;
  line-height: 90rpx;
  overflow-y: hidden;
  margin-bottom: 20rpx;
  position: sticky;
  top: 0;
  background: #fff;
  z-index: 100;
}

.every {
  background: skyblue;
  border-bottom: 1px solid rebeccapurple;
  height: 1500rpx;
}

说明:只是初步实现了效果,可能不是很完善,欢迎大佬讨论交流

觉得不错,赏个关注呗😀,不胜感激Thanks♪(・ω・)ノ

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值