首頁  >  文章  >  web前端  >  BetterScroll在行動裝置上滾動場景的應用

BetterScroll在行動裝置上滾動場景的應用

小云云
小云云原創
2018-02-09 13:54:361642瀏覽

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 &#39;better-scroll&#39;
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('pullingDown', () => {
 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 开放的众多选项、方法和事件,其实,就是提供了一种让我们更加快捷、灵活、精准时机地处理滚动的能力。

相关推荐:

微信小程序YDUI的ScrollTab组件滚动选项卡效果详解

jquery使用iscroll实现上拉、下拉加载刷新实例分享

vue滚动轴插件better-scroll详解

以上是BetterScroll在行動裝置上滾動場景的應用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn