• 媒体品牌
    爱范儿
    关注明日产品的数字潮牌
    APPSO
    先进工具,先知先行,AIGC 的灵感指南
    董车会
    造车新时代,明日出行家
    玩物志
    探索城市新生活方式,做你的明日生活指南
  • 知晓云
  • 制糖工厂
    扫描小程序码,了解更多

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

小程序

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,一扫即用的小程序大全。微信公众号「知晓程序」,做中国最好的小程序报道。

本篇来自栏目

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