分享微信小程序中实现sticky效果的列表页

首先什么是sticky效果呢

具体参照饿了么APP的商品列表页(小程序版本发现并未实现)
具体的效果及实现能够查看一下这个demo => sticky demo on codepen
简单地说就是标题会有粘黏的效果,向下滑动时跟着列表走,向上滑动到顶部时将会固定在顶部。html

可是若是在不考虑兼容性的状况下(IOS6以上、 Safari9.1+、 chrome56+)
其实从CSS3开始有一个position属性sticky就能实现这种效果vue

{
    position: sticky;
    top: 0;
}复制代码

只须要这两行就能实现,然而...然而兼容性那是至关的差,那么好用的一个属性为何兼容性那么差呢?node

那么饿了么的商品列表页在小程序中实有哪些步骤呢?

  1. 利用scroll-view里的scroll-into-view属性,具体可查看小程序的文档
  2. 实现sticky效果(可参照 codepen 的 demo)
  3. 获取每一个scroll-into-view的scrollTop
  4. 监听scroll的滚动,并改变scroll-into-view

下来来让咱们看一下具体该如何实现

<scroll-view scroll-y class="left-wrapper" id="left">
  <view wx:for="..." bindtap="..."></view>
  <!--这里是左侧的类型选择-->
</scroll-view>
<scroll-view scroll-y
             class="right-wrapper"
             bindscroll="onScroll"
             scroll-into-view="{{toView}}"
             id="right">
  <view wx:for="{{items}}" wx-for-item="item" class="lists" id="{{item.title}}">
    <view class="type-title" style="{{style}}">
      <!-- 这个就是ticky header部分 -->
      {{item.title}}
    </view>
    <view class="content">
      <view wx:for="{{item.child}}" class="item">
        <!--这里是须要展现具体的列表项-->
      </view>
    </view>
  </view>
</scroll-view>复制代码

左侧列表页没什么好讲的,无非就是按下某个类型,给上一个checked样式,而后改变toView(关键)的值。
那么toView是什么呢?toView的值是和scroll-view里面你须要跳转的view的id对应起来的,也就是代码中的这个idgit

<view wx:for="{{items}}" wx-for-item="item" class="lists" id="{{item.title}}">复制代码

因此当左侧按下对应的按钮之后,右侧的scroll就会跳转到相应id的scroll-into-view里面,
其实到目前为止已经实现了sticky header + 跳转的问题了
可是...
若是滑动右侧的滚动条的话,左侧的数据如何跟着变化呢?
假如不是小程序的话应该不少人都知道怎么作,无非就是监听滚动条,判断滚动条的位置,而后根据区域去改变左侧的选择。
可是...
小程序若是得到scroll-into-view在scroll-view里面的位置呢???
小程序是没有相似document.getElementById()这种Dom操做的
也无法使用JQuery的$去快捷地获取scrollTop的
也不能像vue同样直接操做$el的
还好小程序在1.4时开放了一个接口wx.createSelectorQuery()github

wx.createSelectorQuery()
返回一个SelectorQuery对象实例。能够在这个实例上使用select等方法选择节点,并使用boundingClientRect等方法选择须要查询的信息。chrome


nodesRef.boundingClientRect([callback])
添加节点的布局位置的查询请求,相对于显示区域,以像素为单位。其功能相似于DOM的getBoundingClientRect。返回值是nodesRef对应的selectorQuery。
返回的节点信息中,每一个节点的位置用left、right、top、bottom、width、height字段描述。若是提供了callback回调函数,在执行selectQuery的exec方法后,节点信息会在callback中返回。
而后能够经过这个方法拿到全部的scroll-into-view的位置小程序

let query = wepy.createSelectorQuery()
for (let i = 0; i < this.types.length; ++i) {
  let id = this.types[i]
  query.select(`#${id}`).boundingClientRect((rect) => {
    this.scrollTops[id] = rect.top
  }).exec()
}复制代码

特别注意
这个操做必须得放在onReady ()的时候去作,不然将没法获得rect属性
获得这个属性之后其实就很好操做了,直接上代码了bash

onScroll (event) {
  // 若是是右侧的滚动view
  if (event.currentTarget.id === 'right') {
    // 判断滚动的方向
    let top = event.detail.scrollTop
    this.dir = this.currentTop < top ? 'down' : 'up'
    this.currentTop = top
    // 判断当前滚动条所在区域,若是不在当前区域则进行跳转
    if (top > this.scrollTops[this.getNextView()] &&
        this.dir === 'down' &&
        this.checked < this.types.length - 1) {
      this.setChecked(this.checked + 1)
    }
    if (top < this.scrollTops[this.toView] &&
        this.dir === 'up' &&
        this.checked > 0) {
      this.setChecked(this.checked - 1)
    }
  }
}复制代码

而后一个简单的具备sticky效果的商品列表页跳转功能就实现了。markdown

  1. scroll-view必须设置高度,不然在IOS上将没法使用scroll-into-view跳转
  2. 使用createSelectorQuery必须在页面渲染完成之后

存在问题

  1. scroll会有个惯性运动,这时候按左侧的按钮切换scroll-into-view会和onScroll事件发生一些冲突,测试IOS存在有该问题,但愿大神给予些指导意见。

说明

因为采用了wepy构建的小程序,因此在部分代码上会和小程序有出入(改过一些),主要是思路。
顺便丢个wepy的github
wepy的本意是但愿小程序能像vue同样开发,因为本人一直在用vue作项目,因此用wepy开发小程序会顺手一些,可是wepy虽然尽力贴合vue,但在某些设计上存在着必定的问题,但相对来讲比直接开发小程序用起来舒服一些。app

碎碎念...谁能教教我怎么优雅地写好Markdown呢T.T

Github: github.com/lyh2668AuthBy: lyh2668

相关文章
相关标签/搜索