舒服的小程序吸顶动画

前言

今天想优化下用户体验:给小程序商品列表页顶部的标签栏增加个吸顶动画。逻辑是检测用户下滑行为时不吸顶,上滑时吸顶,标签栏未滑离视窗时不处理。并对滑动的处理方法增加节流处理,以优化性能。

一、处理页面滚动

1.1 页面逻辑

页面page_name.js

// ...
onPageScroll(e){
	this.selectComponent('#goods_list').data._handleScroll(e)
}
// ...

因为业务需要,商品列表goods_list被我封装成组件形式,所以需要调用组件内的方法来处理。可能有人好奇,为什么组件方法名前有一般用来表示私有方法的下划线_,却还被外部调用,后面会进行说明。

1.2 商品列表逻辑

商品列表组件goods_list.js

import utils from '../../utils/utils'
const HEIGHT_TAB = 70 // 标签栏的高度
// ...
options: {
    pureDataPattern: /^_/, // 纯数据字段的正则
},
data:{
	_scrollTop:0, // 页面滚动的距离
	_handleScroll:_ =>{}, // 防抖处理后的
	isSticky:false, // 标签栏是否是吸顶状态
},

lifeTimes(){
  attached() {
    // 组件挂载时,设置处理滚动的函数
    this._setHandleScroll()
  },
},
methods(){
  _setHandleScroll() {
      this.data._handleScroll = utils.throttle(
        e => {
          const nextScrollTop = e.scrollTop
          const prevScrollTop = this.data._scrollTop
          if (nextScrollTop > prevScrollTop) {
            this.setData({
              isSticky: false,
            })
          } else if (nextScrollTop < prevScrollTop && nextScrollTop > HEIGHT_TAB) {
            this.setData({
              isSticky: true,
            })
          }
          this.setData({
            _scrollTop: nextScrollTop,
          })
        },
        200,
        this
      )
  },
},
// ...  

1.3 节流逻辑

utils.js

/**
   * 
   * @param fn 原函数
   * @param gapTime 间隔时间
   * @param context 上下文
   */
  throttle(fn, gapTime, context) {
    let prev = Date.now()
    return function () {
      let args = arguments
      let now = Date.now()
      if (now - prev > gapTime) {
        prev = now
        fn.apply(context, args)
      }
    }
  }

tips:

  1. 小程序中,因为页面、组件上下文的关系,需要在方法内部设置防抖函数,如上文所示:attached时,赋值_handleScroll为处理函数(这里可以进一步展开讲,关于小程序的上下文和防抖节流的原理,后面可能会出一篇);
  2. 为了性能考虑,对于不需要与渲染相关的data,用pureDataPattern匹配这些data,以减小页面的重绘repaint与回流reflow,在我的项目中此类data都是以_开头的,所以出现了前文中外部调用组件_开头方法的问题

二、吸顶动画处理

goods_list.wxml


<view class="goods-tab {{isSticky ? 'sticky' :''}}">
  <view
    wx:for="{{tabList}}"
    wx:key="sortStyle"
    class="item {{sortStyle === item.sortStyle ? 'active':''}}"
    bind:tap="clickTabItem"
    data-sort-style="{{item.sortStyle}}"
  >
    <view class="title">{{item.title}}view>
    <view class="sub-title">{{item.subTitle}}view>
  view>
view>

goods_list.scss:

.goods-tab {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 30rpx 24rpx 20rpx 24rpx;
  background: #f8f8f8;
  transition: all 0.2s;
  z-index: 1003;
  position: sticky; // 动作前后position保持一致,有相同属性的变化才能有过渡动画
  top: -146rpx; // 标签栏离开视窗时的位置
  width: 750rpx;
  &.sticky {
    position: sticky;
    top: 0rpx;
  }
  // ...
}

你可能感兴趣的:(微信小程序,JavaScript,CSS)