开发 | 餐饮小程序必备!教你轻松做出像「饿了么」一样的点餐界面

小程序

2017-11-29 19:00

文 | zyh2668

知晓程序注:

许多购物、外卖小程序,都会做「分栏」设计,即在左侧展示商品分类、右侧展示分类下的具体商品。

如何将分类栏固定在屏幕上呢?使用 sitcky 特性,或许是个方案。

今天,知晓程序就来为大家讲解,如何在小程序中使用 sticky 的方法,将页面元素固定在屏幕上。

关注「知晓程序」微信公众号,回复「开发」,获取小程序优化秘籍。


什么是 sticky 效果?

简单地说,sticky 就是标题栏的「粘粘」效果,向下滑动时跟着列表走、向上滑动到顶部时将会固定在顶部。

顶部的蓝色条幅,就是 sticky 后的效果

如果不考虑不同浏览器兼容性,CSS 3 就有一个 position: sticky 属性,就能实现这种效果。

{
  position: sticky;
  top: 0;
}

只需要这两行就能实现,然而…… 在不同浏览器中,这个属性的兼容性,那是相当的差。

在小程序里,如何实现固定效果?

在小程序里实现 sticky 效果,我们需要利用小程序 scroll-view 组件里的 scroll-into-view 属性

首先,我们需要获取每个 scroll-into-viewscrollTop,并且监听 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 里面你需要跳转的 viewid 对应起来的,也就是以下代码中的 id

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

当用户按下左侧对应的按钮,右侧的 scroll 就会跳转到相应 idscroll-into-view 里面。

到目前为止,我们已经实现了 sticky header + 跳转的问题了。但如果滑动右侧的滚动条的话,左侧的数据如何跟着变化呢?

假如不是小程序的话,应该很多人都知道怎么做——无非就是监听滚动条,判断滚动条的位置,然后根据区域去改变左侧的选择。但是,小程序如何获得 scroll-into-viewscroll-view 里面的位置呢?

众所周知,小程序是没有类似 document.getElementById() 这种 DOM 操作的,也没法使用 jQuery 的 $ 对象,快捷获取 scrollTop,还不能像 vue 一样,直接操作 $el

还好,小程序基础库 1.4.x 开放了一个接口:wx.createSelectorQuery()

使用这个接口,小程序将会返回一个 SelectorQuery 对象实例。可以在这个实例上使用 select 等方法选择节点,并使用 boundingClientRect 等方法选择需要查询的信息。

nodesRef.boundingClientRect([callback])

添加节点的布局位置的查询请求,相对于显示区域,以像素为单位。其功能类似于 DOM 的 getBoundingClientRect。返回值是 nodesRef 对应的 selectorQuery

返回的节点信息中,每个节点的位置用 leftrighttopbottomwidthheight 字段描述。如果提供了 callback 回调函数,在执行 selectQueryexec 方法后,节点信息会在 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 属性。

得到这个属性以后其实就很好操作了,直接上代码:

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 效果的商品列表页,以及分类跳转功能,就实现了。

坑与问题

首先,scroll-view 必须设置高度,否则在 iOS 上,将无法使用 scroll-into-view 跳转。另外,页面渲染完成后,才能使用 createSelectorQuery

此外,scroll 会有个惯性运动。这时候,按左侧的按钮切换 scroll-into-view 会和 onScroll 事件发生一些冲突,实测在 iOS 存在有该问题,希望大神给予些指导意见。

最后的话

由于采用了 wepy 构建的小程序,所以在部分代码上会有出入或相似的地方。但我们主要学习的是思路。

wepy 的本意是希望小程序能像 vue 一样开发,由于本人一直在用 vue 做项目,所以用 wepy 开发小程序会顺手一些。

但是 wepy 虽然尽力贴合 vue,但在某些设计上存在着一定的问题。不过,使用 wepy 已经比直接开发小程序用起来舒服一些。

关注「知晓程序」公众号,在微信后台回复「开发」,让你的小程序性能再上一层楼。

登录,参与讨论前请先登录

评论在审核通过后将对所有人可见

正在加载中

小程序商店 minapp.com,一扫即用的小程序大全。微信公众号「知晓程序」,做中国最好的小程序报道。

本篇来自栏目

解锁订阅模式,获得更多专属优质内容