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 方法和事件。
以下介紹幾個常用的選項、方法和事件。
捲軸
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实现上拉、下拉加载刷新实例分享
以上是BetterScroll在行動裝置上滾動場景的應用的詳細內容。更多資訊請關注PHP中文網其他相關文章!