一款好用的移动端滚动插件BetterScroll

目录
  • 让滚动更流畅
    • BetterScroll 的滚动体验
    • 惯性滚动
    • 边缘回弹
  • 如何应用于各种需求场景
  • 普通滚动列表
    • 滚动条
    • 下拉刷新
    • 上拉加载
  • 选择器
  • 轮播图
  • 特殊场景
    • 索引列表
    • 开屏引导
    • 自由滚动
  • 小结

作者:滴滴webapp架构组-付楠

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 在各种场景下的姿势。

普通滚动列表

比如,有如下列表:

<div ref="wrapper" class="list-wrapper">
  <ul class="list-content">
    <li @click="clickItem($event,item)" class="list-item" v-for="item in data">{{item}}</li>
  </ul>
</div>

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

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 方法和事件。

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

滚动条

scrollbar选项,用来配置滚动条,默认为 false。当设置为 true 或者是一个 Object,开启滚动条。还可以通过 fade 属性,配置滚动条是随着滚动操作淡入淡出,还是一直显示。

// fade 默认为 true,滚动条淡入淡出
options.scrollbar = true

// 滚动条一直显示
options.scrollbar = {
  fade: false
}

this.scroll = new BScroll(this.$refs.wrapper, options)

具体效果可见普通滚动列表-示例

下拉刷新

pullDownRefresh选项,用来配置下拉刷新功能。当设置为 true 或者是一个 Object 的时候,开启下拉刷新,可以配置顶部下拉的距离(threshold)来决定刷新时机,以及回弹停留的距离(stop)

options.pullDownRefresh = {
  threshold: 50, // 当下拉到超过顶部 50px 时,触发 pullingDown 事件
  stop: 20 // 刷新数据的过程中,回弹停留在距离顶部还有 20px 的位置
}

this.scroll = new BScroll(this.$refs.wrapper, options)

监听 pullingDown 事件,刷新数据。并在刷新数据完成之后,调用 finishPullDown() 方法,回弹到顶部边界

this.scroll.on('pullingDown', () => {
  // 刷新数据的过程中,回弹停留在距离顶部还有20px的位置
  RefreshData()
    .then((newData) => {
      this.data = newData
      // 在刷新数据完成之后,调用 finishPullDown 方法,回弹到顶部
      this.scroll.finishPullDown()
  })
})

具体效果可见普通滚动列表-示例

上拉加载

pullUpLoad选项,用来配置上拉加载功能。当设置为 true 或者是一个 Object 的时候,可以开启上拉加载,可以配置离底部距离阈值(threshold)来决定开始加载的时机

options.pullUpLoad = {
  threshold: -20 // 在上拉到超过底部 20px 时,触发 pullingUp 事件
}

this.scroll = new BScroll(this.$refs.wrapper, options)

监听 pullingUp 事件,加载新数据。

this.scroll.on('pullingUp', () => {
  loadData()
    .then((newData) => {
      this.data.push(newData)
  })
})

具体效果可见普通滚动列表-示例

选择器

wheel选项,用于开启并配置选择器。可配置选择器当前选择的索引(selectedIndex),列表的弯曲弧度(rotate),以及切换选择项的调整时间(adjustTime)。

options.wheel = {
  selectedIndex: 0,
  rotate: 25,
  adjustTime: 400
}

// 初始化选择器的每一列
this.wheels[i] = new BScroll(wheelWrapper.children[i], options)

具体效果可见选择器 - 示例

其中联动选择器,需要监听每个选择列表的选择,来改变其他选择列表。

data() {
   return {
     tempIndex: [0, 0, 0]
   }
},
...
// 监听每个选择列表的选择
this.wheels[i].on('scrollEnd', () => {
  this.tempIndex.splice(i, 1, this.wheels[i].getSelectedIndex())
})
...
// 根据当前选择项,确定其他选择列表的内容
computed: {
  linkageData() {
    const provinces = provinceList
    const cities = cityList[provinces[this.tempIndex[0]].value]
    const areas = areaList[cities[this.tempIndex[1]].value]

    return [provinces, cities, areas]
  }
},

具体效果可见选择器 - 示例中的联动选择器。

轮播图

snap选项,用于开启并配置轮播图。可配置轮播图是否循环播放(loop),每页的宽度(stepX)和高度(stepY),切换阈值(threshold),以及切换速度(speed)。

options = {
  scrollX: true,
  snap: {
    loop: true, // 开启循环播放
    stepX: 200, // 每页宽度为 200px
    stepY: 100, // 每页高度为 100px
    threshold: 0.3, // 滚动距离超过宽度/高度的 30% 时切换图片
    speed: 400 // 切换动画时长 400ms
  }
}

this.slide = BScroll(this.$refs.slide, options)

具体效果可见轮播图 - 示例

特殊场景

除了普通滚动列表、选择器、轮播图等基础滚动场景,还可以利用 BetterScroll 提供的能力,做一些特殊场景。

索引列表

索引列表,首先需要在滚动过程中实时监听滚动到哪个索引的区域了,来更新当前索引。在这种场景下,我们可以使用probeType选项,当此选项设置为 3 时,会在整个滚动过程中实时派发 scroll 事件。从而获取滚动过程中的位置。

options.probeType = 3
this.scroll = new BScroll(this.$refs.wrapper, options)

this.scroll.on('scroll', (pos) => {
  const y = pos.y

  for (let i = 0; i < listHeight.length - 1; i++) {
    let height1 = listHeight[i]
    let height2 = listHeight[i + 1]
    if (-y >= height1 && -y < height2) {
      this.currentIndex = i
    }
  }
})

当点击索引时,使用scrollToElement()方法滚动到该索引区域。

scrollTo(index) {
  this.$refs.indexList.scrollToElement(this.$refs.listGroup[index], 0)
}

具体效果可见索引列表 - 示例

开屏引导

开屏引导,其实就是一种不自动循环播放的横向滚动轮播图而已。

options = {
  scrollX: true,
  snap: {
    loop: false
  }
}

this.slide = BScroll(this.$refs.slide, options)

具体效果可见开屏引导 - 示例。因为此需求场景一般只有移动端才有,所以最好在手机模式下看效果。

自由滚动

freeScroll选项,用于开启自由滚动,允许横向和纵向同时滚动,而不限制在某个方向。

options.freeScroll = true

另外需要注意的是,此选项在 eventPassthrough 设置了保持原生滚动时无效。

具体效果可见自由滚动-示例

小结

BetterScroll 可以用于几乎所有滚动场景,本文仅介绍了在一些典型场景下的使用姿势。

作为一款旨在解决移动端滚动需求的插件,BetterScroll 开放的众多选项、方法和事件,其实,就是提供了一种让我们更加快捷、灵活、精准时机地处理滚动的能力。

到此这篇关于一款好用的移动端滚动插件BetterScroll的文章就介绍到这了,更多相关BetterScroll移动端滚动插件内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

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

    BetterScroll 是一款重点解决移动端各种滚动场景需求的开源插件( GitHub地址 ),适用于滚动列表.选择器.轮播图.索引列表.开屏引导等应用场景. 为了满足这些场景,它不仅支持惯性滚动.边界回弹.滚动条淡入淡出等效果的灵活配置,让滚动更加流畅,同时还提供了很多 API 方法和事件,以便我们更快地实现滚动场景下的需求,如下拉刷新.上拉加载. 由于它基于原生 JavaScript 实现,不依赖任何框架,所以既可以原生 JavaScript 引用,也可以与目前前端 MVVM 框架结合使用

  • 解决betterScroll在vue中存在图片时,出现拉不动的问题

    1.先写一个图片加载的方法 class ImgLoadClass { static preloadImages = (arr) => { //已经加载完的图片数量 let loadeImage = 0 //存放图片的数组 let newImages = [] //处理存入字符串,取得src部分 //let arr = str.match(/src="(.+)"\s{1}/g) //返回一个promise对像 return new Promise((resolve,reject)=

  • 一款好用的移动端滚动插件BetterScroll

    目录 让滚动更流畅 BetterScroll 的滚动体验 惯性滚动 边缘回弹 如何应用于各种需求场景 普通滚动列表 滚动条 下拉刷新 上拉加载 选择器 轮播图 特殊场景 索引列表 开屏引导 自由滚动 小结 作者:滴滴webapp架构组-付楠 BetterScroll是一款重点解决移动端各种滚动场景需求的开源插件(GitHub地址),适用于滚动列表.选择器.轮播图.索引列表.开屏引导等应用场景. 为了满足这些场景,它不仅支持惯性滚动.边界回弹.滚动条淡入淡出等效果的灵活配置,让滚动更加流畅,同时还

  • vue滚动插件better-scroll使用详解

    本文实例为大家分享了vue滚动插件better-scroll的具体代码,供大家参考,具体内容如下 1. 概述 1.1 说明 better-scroll是一款重点解决移动端(已支持PC)各种滚动场景需求的插件.例如淘宝聚划算中的类型选择(女装/家纺/生鲜美食等),没有滚动条显示却实现了滚动功能. 1.2 better-scroll安装 npm install better-scroll --save 安装至项目中 1.3 better-scroll使用 better-scroll常见应用场景(列表

  • 详解 vue better-scroll滚动插件排坑

    BetterScroll号称目前最好用的移动端滚动插件,因此它的强大之处肯定是存在的.要不...哈哈.个人感觉还是很好用的.这篇文章不是笼统的讲 BetterScroll ,而是单讲滚动,想要深入了解它,请移步这里. 滚动原理 better-scroll 是什么滚动原理 better-scroll 是一款重点解决移动端(已支持 PC)各种滚动场景需求的插件.它的核心是借鉴的 iscroll 的实现,它的 API 设计基本兼容 iscroll,在 iscroll 的基础上又扩展了一些 featur

  • vue中利用iscroll.js解决pc端滚动问题

    项目中经常遇到区域超出部分会出现滚动条,滚动条在pc端可以通过鼠标滚轮控制上下,在移动端可以通过鼠标拖动页面进行滚动,这两种场景都是符合用户习惯,然而这种滚动条一般都是竖[vertical]项滚动条,如果pc端出现横向滚动条[horizontal],在不做处理的情况下,你只能用鼠标拖动横向滚动条按钮[scrollerbar]展示滚动区域,而且为了美观,一般滚动条会进行样式编写或者隐藏,那么横向区域默认情况下就没法滚动. 二.描述 现为了解决pc端滚动区域能像移动端一样,能够通过鼠标拖动滚动区域直

  • Vue项目移动端滚动穿透问题的实现

    概述 今天在做 Vue 移动端项目的时候遇到了滚动穿透问题,在网上查资料后,选取了我觉得最好的方法,记录下来供以后开发时参考,相信对其他人也有用. 上层无需滚动 如果上层无需滚动的话,直接屏蔽上层的 touchmove 事件即可.示例如下: <div @touchmove.prevent> 我是里面的内容 </div> 上层需要滚动 如果上层需要滚动的话,那么固定的时候先获取 body 的滑动距离,然后用 fixed 固定,用 top 模拟滚动距离:不固定的时候用获取 top 的值

  • 学习使用jquery iScroll.js移动端滚动条插件

    大家在日常工作中最常用的插件是什么,jQurey?Lazyload?但是这些都是在PC端,但是在移动端最常用的插件莫过于iScroll了,iScroll到底是什么东西,应该怎么用?iScroll是个很强大的插件,我也只是略懂皮毛,这里我们简单的介绍一下. iScroll的产生: iScroll的产生完全是因为移动版webkit浏览器,例如在iPhone,Android 的移动设备上. iScroll的使用方法: iScroll的原理是外层有一个溢出隐藏(overflow:hidden;)的DOM

  • jQuery控制li上下循环滚动插件用法实例(附demo源码下载)

    本文实例讲述了jQuery控制li上下循环滚动插件用法.分享给大家供大家参考,具体如下: /** * * jQuery scrollQ plugin li上下滚动插件 * @name jquery-scrollQ.js * @author Q * @date 2012-03-23 * line 显示li行数 * scrollNum 每次滚动li行数 * scrollTime 滚动速度 单位毫秒 * */ (function($){ var status = false; $.fn.scrollQ

  • 推荐三款不错的图片压缩上传插件(webuploader、localResizeIMG4、LUploader)

    涉及到网页图片的交互,少不了图片的压缩上传,相关的插件有很多,相信大家都有用过,这里我就推荐三款,至于好处就仁者见仁喽: 1.名气最高的WebUploader,由Baidu FEX 团队开发,以H5为主,FLASH为辅,兼容 IE6+,iOS 6+, android 4+,采用大文件分片并发上传,极大的提高了文件上传效率,看了官方文档就知道,能满足你所需要的所有功能,一言以蔽之,大而全:至于缺点,大概就是插件体积太大了,自带样式文件,而且还要依赖jquery类库.详细的教程网上俯拾即是,这里我就

  • 用ES6写全屏滚动插件的示例代码

    这篇文章将介绍如何使用原生 JS (主要使用 ES6 语法)实现全屏滚动插件,兼容 IE 10+.手机触屏,Mac 触摸板优化,支持自定义页面动画,压缩后 gzip 文件只有 2k.完整源码在这 pure_full_page,点这查看demo. 1)前面的话 现在已经有很多全屏滚动插件了,比如著名的 fullPage ,那为什么还要自己造轮子呢? 现有轮子有以下问题: 首先,最大的问题是最流行的几个插件都依赖 jQuery,这意味着在使用 React 或者 Vue 的项目中使用他们是一件十分蛋疼

随机推荐