BetterScroll 在移动端滚动场景的应用

BetterScroll 是一款重点解决移动端各种滚动场景需求的开源插件( GitHub地址 ),适用于滚动列表、选择器、轮播图、索引列表、开屏引导等应用场景。

为了满足这些场景,它不仅支持惯性滚动、边界回弹、滚动条淡入淡出等效果的灵活配置,让滚动更加流畅,同时还提供了很多 API 方法和事件,以便我们更快地实现滚动场景下的需求,如下拉刷新、上拉加载。

由于它基于原生 JavaScript 实现,不依赖任何框架,所以既可以原生 JavaScript 引用,也可以与目前前端 MVVM 框架结合使用,比如,其官网上的示例就是与 Vue 的结合。

首先,让我们来看一下它是怎样让滚动更流畅的吧。

让滚动更流畅

在移动端,如果你使用过 overflow: scroll 生成一个滚动容器,会发现它的滚动是比较卡顿,呆滞的。为什么会出现这种情况呢?

因为我们早已习惯了目前的主流操作系统和浏览器视窗的滚动体验,比如滚动到边缘会有回弹,手指停止滑动以后还会按惯性继续滚动一会,手指快速滑动时页面也会快速滚动。而这种原生滚动容器却没有,就会让人感到卡顿。

BetterScroll 的滚动体验

试一试 BetterScroll 的滚动体验吧。体验地址

可以发现,在增加惯性滚动,边缘回弹等效果之后,明显流畅、舒服了很多。那么,这些效果是怎么实现的呢?

惯性滚动

BetterScroll 在用户滑动操作结束时,还会继续惯性滚动一段。首先看一下源码中的 BScroll.prototype._end 函数,这是 touchend、mouseup、touchcancel、mousecancel 事件的处理函数,也就是用户滚动操作结束时的逻辑。

BScroll.prototype._end = function (e) { ... if (this.options.momentum && duration < this.options.momentumLimitTime && (absDistY > this.options.momentumLimitDistance || absDistX > this.options.momentumLimitDistance)) { let momentumX = this.hasHorizontalScroll ? momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options) : {destination: newX, duration: 0} let momentumY = this.hasVerticalScroll ? momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options) : {destination: newY, duration: 0} newX = momentumX.destination newY = momentumY.destination time = Math.max(momentumX.duration, momentumY.duration) this.isInTransition = 1 } ... }

以上代码的作用是,在用户滑动操作结束时,如果需要开启了惯性滚动,用 momentum 函数计算惯性滚动距离和时间。该函数,根据用户滑动操作的速度和 deceleration选项 ——惯性减速来计算滚动距离,至于滚动时间,也是一个可配置的选项。

function momentum(current, start, time, lowerMargin, wrapperSize, options) { ... let distance = current - start let speed = Math.abs(distance) / time ... let duration = swipeTime let destination = current + speed / deceleration * (distance < 0 ? -1 : 1) ... }

边缘回弹

超过边缘时的回弹,有两个处理步骤,第一步是滚动到超过边界时速度要变慢,第二步是回弹到边界。其中,第一步是在源码的 BScroll.prototype._move 函数,这是 touchmove 和 mousemove 事件的处理函数,也就是在用户滑动操作过程中的逻辑。

// Slow down or stop if outside of the boundaries if (newY > 0 || newY < this.maxScrollY) { if (this.options.bounce) { newY = this.y + deltaY / 3 } else { newY = newY > 0 ? 0 : this.maxScrollY } }

第二步是调用 BScroll.prototype.resetPosition 函数,回弹到边界。

BScroll.prototype.resetPosition = function (time = 0, easeing = ease.bounce) { ... let y = this.y if (!this.hasVerticalScroll || y > 0) { y = 0 } else if (y < this.maxScrollY) { y = this.maxScrollY } ... this.scrollTo(x, y, time, easeing) ... }

流畅的滚动仅仅是基础,BetterScoll 真正的能力在于:提供了大量通用 / 定制的option 选项 、API 方法和事件,让各种滚动需求实现起来更高效。

如何应用于各种需求场景

下面,以结合 Vue 的使用为例,说一下 BetterScroll 在各种场景下的姿势。

普通滚动列表

比如,有如下列表:

{{item}}

我们想要让它垂直滚动,只需要对该容器进行简单的初始化。

import BScroll from 'better-scroll' const options = { scrollY: true // 因为scrollY默认为true,其实可以省略 } this.scroll = new BScroll(this.$refs.wrapper, options)

对于 Vue 中使用 BetterScroll,有一个需要注意的点是,因为在 Vue 模板中列表渲染还没完成时,是没有生成列表 DOM 元素的,所以需要在确保列表渲染完成以后,才能创建 BScroll 实例,因此在 Vue 中,初始化 BScroll 的最佳时机是 mouted 的 nextTick。

// 在 Vue 中,保证列表渲染完成时,初始化 BScroll mounted() { setTimeout(() => { this.scroll = new BScroll(this.$refs.wrapper, options) }, 20) },

初始化之后,这个 wrapper 容器就能够优雅地滚动了,并且可以通过 BScroll 实例 this.scroll 使用其提供的 API 方法和事件。

下面介绍几个常用的选项、方法和事件。

滚动条

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wyzxdd.html