一款好用的移動端滾動外掛BetterScroll
目錄
- 讓滾動更流暢
- BetterScroll 的滾動體驗
- 慣性滾動
- 邊緣回彈
- 如何應用於各種需求場景
- 普通滾動列表
- 滾動條
- 下拉重新整理
- 上拉載入
- 選擇器
- 輪播圖
- 特殊場景
- 索引列表
- 開屏引導
- 自由滾動
- 小結
作者:滴滴webapp架構組-付楠
BetterScroll 是一款重點解決移動端各種滾動場景需求的開源外掛(地址),適用於滾動列表、選擇器、輪播圖、索引列表、開屏引導等應用場景。
為了滿足這些場景,它不僅支援慣性滾動、邊界回彈、滾動條淡入淡出等效果的靈活配置,讓滾動更加流暢,同時還提供了很多 API 方法和事件,以便我們更快地實現滾動場景下的需求,如下拉重新整理、上拉載入。
由於它基於原生 實現,不依賴任何框架,所以既可以原生 Script 引用,也可以與目前前端 MVVM 框架結合使用,比如,其官網上的示例就是與 的結合。
首先,讓我們來看一下它是怎樣讓滾動更流暢的吧。
讓滾動更流暢
在移動端,如果你使用過 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,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,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選項,用來www.cppcns.com配置滾動條,預設為 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] } },... // 監聽每個選擇列表的選擇 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: trTVEPTqsue,// 開啟迴圈播放 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移動端滾動外掛內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!