方案说明:

方案1:整个页面滚动,滚动至某个位置fixed图中“顶部box2”,分页页面触底加载

方案2:页面高度为屏幕高度,商品部分使用scroll-view,scroll-view初始高度为屏幕高度-顶部高度,只滚动scroll-view。

  思路说明:

  1 将整个页面分为上下两部分,整个页面高度100vh(原因1:scroll-view高度需要固定高度;原因2:出现两个滚动条)

  2 页面上半部分包括banner(box1)以及固定的搜索及tab(box2)

  3 根据顶部box的高度,算出下面scroll-view的高度(windowHieght - 200)

  4 scroll-view滑动到 顶部box1+margin10的高度,将box1隐藏,box2动画移至顶部;下面scroll高度+滚动高度(或box1高度) + margin10高度(确保scroll的商品吸顶之后任然沾满屏幕)

方案3:使用插件

 

选择的是方案2,为什么不选择方案1,我们来剖析一下。

方案1适合页面交互比较简单,根据页面滚动高度隐藏展示即可。

  场景1:tab吸顶之后,切换tab请求数据,页面就会渲染为最初样式,不会吸顶。(请求会重新setData数据,有些数据有多有少)

 

复制以下代码可以直接演示demo效果

demo.wxml

<!--pages/demo/demo.wxml-->
<view class="wrap">
  <view class="top-box" style="{{boxStyle}}">
    <view class="top-box1" style="{{box1Style}}">顶部box1</view>
    <!-- <view class="top-box2"></view> -->
    <scroll-view class="top-box2" scroll-into-view="{{scrollId}}" scroll-x="true"scroll-with-animation="true" >
      <block wx:for="{{cates}}" wx:key="index">
        <view class="{{item.id === currentId?'cate-item-act cate-item':'cate-item'}}" data-id="{{item.id}}" id="good{{item.id}}" bindtap="cateChange">{{item.name}}</view>
      </block>
    </scroll-view>
  </view>
  <scroll-view scroll-y="true" class="scroll-con" style="{{scrollViewStyle}}" bindscroll="goodsViewScroll" bindscrolltoupper="goodsViewScrollTop">
    <view class="scroll-con-item" wx:for="{{cates}}" wx:key="index">{{item.name}}</view>
  </scroll-view>
</view>

demo.js

Page({
  data: {
    cates:[
      {id:null,name:'全部'},
      {id:1,name:'分类1'},
      {id:2,name:'分类2'},
      {id:3,name:'分类3'},
      {id:4,name:'分类4'},
      {id:5,name:'分类5'},
      {id:6,name:'分类6'},
      {id:7,name:'分类7'},
      {id:8,name:'分类8'}
    ],
    currentId:null,
    serviceList:[
      {id:1,name:'1'},
      {id:2,name:'2'},
      {id:3,name:'3'},
      {id:4,name:'4'},
      {id:5,name:'5'},
      {id:6,name:'6'},
      {id:7,name:'7'},
      {id:8,name:'8'}
    ],
    scrollId:null,//滑动id,切换tab效果
    animationStyle:'',
    isNeedFixed:false
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    let that = this;
    wx.getSystemInfo({
      success: function (res, rect) {
        that.setData({
          // 商品scroll高度 = 可使用窗口 - (顶部box的高度+margin20 -20(底部留白))
          scrollViewHeight: parseInt(res.windowHeight - 220 -20),
          scrollViewStyle:`height:${parseInt(res.windowHeight - 220-20)}px`
        })
      }
    })
  },
  cateChange(e){
    let currentId = e.currentTarget.dataset.id;
    let scrollId = e.currentTarget.id;
    this.setData({
      currentId,
      scrollId
    })
  },
  // 加this.data.isNeedFixed条件防止频繁的setdata
  // 1 隐藏box1,box2会自动吸顶 box2置顶
  // 2 设置scroll-view高度+120, 设置顶部box高度为box2高度
  goodsViewScroll(e){
    console.log(e.detail.scrollTop, this.data.isNeedFixed)
    if(e.detail.scrollTop >= 120 ){
      console.log('可以动画调整位置了')
      this.setData({
        isNeedFixed:true,
        box1Style:`height:0px;`,
        boxStyle:`height:80px;`,
        scrollViewStyle: `height:${this.data.scrollViewHeight + 120}px`,  
      }
    }
    // if(e.detail.scrollTop < 120 ) {
    //   console.log('需要保持原样')
    //   this.setData({
    //     isNeedFixed:false,
    //     box1Style:`height:110px;`,
    //     boxStyle:`height:200px;`,
    //     scrollViewStyle: `height:${this.data.scrollViewHeight}px`,
    //   },()=>{
    //     wx.pageScrollTo({
    //       scrollTop: 0,
    //     })
    //   })
    // }
  },
goodsViewScrollTop(e){
this.setData({ isNeedFixed:false, box1Style:`height:110px;`, boxStyle:`height:200px;`, scrollViewStyle: `height:${this.data.scrollViewHeight}px`, }) } })

demo.wxss

.wrap {
  height: 100vh;
}
.top-box {
  height: 200px;
  height: 200px;
  background-color: #fff;
  border: 1px solid #d1d1d1;
  transition:height 0.2s;
    -webkit-transition:height 0.2s; /* Safari */
}
.top-box1 {
  height: 110px;
  width: 100%;
  margin-bottom: 10px;
  background-color: #3293FF;
  overflow: hidden;
  transition:height 0.2s;
  -webkit-transition:height 0.2s; /* Safari */
}
.top-box2 {
  height: 80px;
  width: 100%;
  background-color: #ffbe32;
  white-space: nowrap;
  padding: 50rpx 0;
  box-sizing: border-box;
}
.top-box2 .cate-item {
  display: inline-block;
  padding: 10rpx 20rpx;
  font-size: 26rpx;
  margin-right: 20rpx;
  color: #767A84;
}
.top-box2 .cate-item:last-child{
  margin-right: 0rpx;
}
.top-box2 .cate-item-act {
  background: #3293FF;
  color: #fff;
  border-radius: 48rpx;
}
.scroll-con {
  padding: 0 10px;
  margin-top: 20px;
  box-sizing: border-box;
  background-color: #fff;
}
.scroll-con-item {
  height: 100px;
  width: 100%;
  background-color: salmon;
  margin-bottom: 10px;
}
.ani-btn {
  display: inline-block;
  padding: 20rpx;
  margin: 10rpx;
  border: 1px solid #d1d1d1;
}
@keyframes move{ from{transform: translateY( 30px)} to {transform: translateY( 0px)}}

 

说明1:scroll-into-view 设置哪个方向可滚动,则在哪个方向滚动到该元素

  scroll-view设置x轴滚动到scrollId位置 scroll-x="true" scroll-into-view="{{scrollId}}"    

  item子元素设置 id="good{{item.id}}" 由于id不能已数字开头,所以前面拼了"good"

 说明2:为什么要在bindscrolltoupper触顶事件中处理初始化样式,而不是在 bindscroll 的时候处理?

  使用bindscroll处理,滑动会有来回闪动的情况

 这些只是大致思路,还有很多细节需要处理和考.......

 

posted on 2022-10-10 14:18  努力中的小白羊  阅读(603)  评论(0编辑  收藏  举报