开发 | 餐饮小程序必备!教你轻松做出像「饿了么」一样的点餐界面
文 | zyh2668
知晓程序注:
许多购物、外卖小程序,都会做「分栏」设计,即在左侧展示商品分类、右侧展示分类下的具体商品。
如何将分类栏固定在屏幕上呢?使用 sitcky 特性,或许是个方案。
今天,知晓程序就来为大家讲解,如何在小程序中使用 sticky 的方法,将页面元素固定在屏幕上。
关注「知晓程序」微信公众号,回复「开发」,获取小程序优化秘籍。
什么是 sticky 效果?
简单地说,sticky 就是标题栏的「粘粘」效果,向下滑动时跟着列表走、向上滑动到顶部时将会固定在顶部。
顶部的蓝色条幅,就是 sticky 后的效果
如果不考虑不同浏览器兼容性,CSS 3 就有一个 position: sticky
属性,就能实现这种效果。
{
position: sticky;
top: 0;
}
只需要这两行就能实现,然而…… 在不同浏览器中,这个属性的兼容性,那是相当的差。
在小程序里,如何实现固定效果?
在小程序里实现 sticky 效果,我们需要利用小程序 scroll-view
组件里的 scroll-into-view
属性。
首先,我们需要获取每个 scroll-into-view
的 scrollTop
,并且监听 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
对应起来的,也就是以下代码中的 id
。
<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.x 开放了一个接口:wx.createSelectorQuery()
。
使用这个接口,小程序将会返回一个 SelectorQuery
对象实例。可以在这个实例上使用 select
等方法选择节点,并使用 boundingClientRect
等方法选择需要查询的信息。
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
属性。
得到这个属性以后其实就很好操作了,直接上代码:
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 已经比直接开发小程序用起来舒服一些。
关注「知晓程序」公众号,在微信后台回复「开发」,让你的小程序性能再上一层楼。