摘要:是一款重點解決移動端各種滾動場景需求的開源插件地址,有下列功能支持滾動列表,下拉刷新,上拉刷新,輪播圖,等功能。為了滿足這些功能,通過使用慣性滾動邊界回彈滾動條淡入淡出來確保滾動的流暢。貝瑟爾函數可以去看看,他讓動畫不再那么突兀。
BetterScroll 是一款重點解決移動端各種滾動場景需求的開源插件(GitHub地址),有下列功能支持滾動列表,下拉刷新,上拉刷新,輪播圖,slider等功能。
為了滿足這些功能,better-scroll通過使用慣性滾動、邊界回彈、滾動條淡入淡出來確保滾動的流暢。同時還支持很多API和事件,具體支持的事件可以查看官網講的非常詳細。
由于它基于原生JavaScript 實現,不依賴任何框架,所以既可以原生 JavaScript 引用,也可以與目前前端 MVVM 框架結合使用,比如,其官網上的示例就是與 Vue 的結合。
再講如何使用的之前,我們先來了解一下他的滾動原理:在瀏覽器中的滾動中,當內容的高度高于外邊容器的高度的時候也就出現了滾動條,我們可以通過使用滾動條來看到超出的部分.
better-scroll的原理正是基于這里,內容部分的寬度/高度必須大于外部寬度/高度。所以在使用
的時候外部容器的需要設置固定寬度,還有一個問題需要設置overflow:hidden,這是因為為了隱藏超出部分。然后就是什么時候對better-scroll進行初始化,這個有點麻煩,但是所幸,作者已經在vue框架下進行封裝,我們只需要像個麻瓜一樣往里邊填東西就行了。但是有一點需要注意:滾動的元素只能是第一個容器的第一個元素。源碼如下:
// this.scroller就是滾動的內容,this.wrapper是容器 this.scroller = this.wrapper.children[0]
如果我們需要滾動多個內容怎么辦呢,就用一個元素將其包裹住,讓他成為容器的第一個子元素就行了。如何使用講完了,我們來講講源碼,畢竟這是一個源碼解析的文章
核心代碼: 1、scrollToscrollTo()函數是better-scroll非常核心的一個函數,事實上我們在調用scrollToElement的
時候,內部進行的操作還是scrollTo函數
BScroll.prototype.scrollTo = function (x, y, time=0, easing = ease.bounce) { // useTransition是否使用css3 transition,isInTransition表示是否在滾動過程中 // this.x表示translate后的位置或者初始化this.x = 0 this.isInTransition = this.options.useTransition && time > 0 && (x !== this.x || y !== this.y) // 如果使用的transition,就調用一系列transition的設置,默認是true if (!time || this.options.useTransition) { this._transitionProperty() this._transitionTimingFunction(easing.style) this._transitionTime(time) // 這個函數會更改this.x this._translate(x, y) // time存在protoType表示不僅在屏幕滑動的時候, momentum 滾動動畫運行過程中實時派發 scroll 事件 if (time && this.options.probeType === 3) { // 這個函數的作用是派發scroll事件 this._startProbe() } // wheel用于picker組件設置,不用管 if (this.options.wheel) { if (y > 0) { this.selectedIndex = 0 } else if (y < this.maxScrollY) { this.selectedIndex = this.items.length - 1 } else { this.selectedIndex = Math.round(Math.abs(y / this.itemHeight)) } } else { // 進行動畫this._animate this._animate(x, y, time, easing.fn) } } };
我們來依次看看這個函數,其中簡單的操作用代碼注明,也就不做太多的描述,其中例如this._transition這種有關transform的都是改變他的位置而已,這里我需要說明一下,我們在制作輪播圖的時候,別去使用transform這種方法來做輪播圖,因為當我們需要獲取transform屬性值的時候,你會獲取到的值是一個非常奇怪的矩陣,得到translateX或者translateY的值是一件非常痛苦的事,可以看看作者是如何獲取transform的值的,
matrix = matrix[style.transform].split(")")[0].split(", ") x = +(matrix[12] || matrix[4]) y = +(matrix[13] || matrix[5])
我是一臉蒙蔽,要是你覺得你水平很高當我沒說。this.options.probeType這個probeType配置表明的是我們需要在什么情況下派發scroll事件,在better-scroll的原理中是默認阻止瀏覽器的默認行為的,那我們是如何派發事件的呢?
export function tap(e, eventName) { let ev = document.createElement("Event") ev.initEvent(eventName, true, true) e.target.dispatchEvent(ev) }
創建一個element,然后初始化,然后派發事件,我們就可以像addEventListener("click", fn, false)這樣的方式來監聽事件addEventListener(eventName, fn, false)。這兒有一個參數叫easing,我們來看看easing是什么
下面是一個easing的一個選項:
bounce: { style: "cubic-bezier(0.165, 0.84, 0.44, 1)", fn: function (t) { return 1 - (--t * t * t * t) } }
可以看到easing通過貝瑟爾函數,和fn讓我們的動畫顯得不是那么僵硬。貝瑟爾函數可以去看看,他讓動畫不再那么突兀。
2、refresh函數在實際開發中,有時候從后端請求到數據后,我們dom結構發生變化,所以需要調用refresh方法,來看看他是什么玩意
BScroll.prototype.refresh = function () { // return getBoundingRect getRect() let wrapperRect = getRect(this.wrapper) this.wrapperWidth = wrapperRect.width this.wrapperHeight = wrapperRect.height let scrollerRect = getRect(this.scroller) this.scrollerWidth = scrollerRect.width this.scrollerHeight = scrollerRect.height const wheel = this.options.wheel // wheel用于picker組件設置 if (wheel) { this.items = this.scroller.children this.options.itemHeight = this.itemHeight = this.items.length ? this.scrollerHeight / this.items.length : 0 if (this.selectedIndex === undefined) { this.selectedIndex = wheel.selectedIndex || 0 } this.options.startY = -this.selectedIndex * this.itemHeight this.maxScrollX = 0 this.maxScrollY = -this.itemHeight * (this.items.length - 1) } else { // 允許滑動的距離 this.maxScrollX = this.wrapperWidth - this.scrollerWidth this.maxScrollY = this.wrapperHeight - this.scrollerHeight } // 滾動原理容器的寬度小于scroller的寬度 // scrollX設置為true表示可以橫向滾動 this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0 this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0 // 如果水平不存在的話 if (!this.hasHorizontalScroll) { this.maxScrollX = 0 this.scrollerWidth = this.wrapperWidth } if (!this.hasVerticalScroll) { this.maxScrollY = 0 this.scrollerHeight = this.wrapperHeight } this.endTime = 0 // 移動方向 this.directionX = 0 this.directionY = 0 // return el.offsetLeft // el.offsetLeft是距離父容器的距離 // el.getBoundingClientRect()返回的是距離頁面的距離 this.wrapperOffset = offset(this.wrapper) // 切換到refresh事件 this.trigger("refresh") // 重置位置 this.resetPosition() }
當我們的dom結構發生變化的時候,我們就需要重新計算父容器和容器的大小了,這樣就可以重新渲染了,這個函數沒什么太難理解的部分,需要注意的是getBoundingClientRect()方法返回元素的大小及其相對于視口的位置。他同element.style獲取的有些不同getBoundingClientRect()獲取到的值是相對視口左上角,意思是說在獲取right值的時候,事實上是left+element.clientWidth。而且getBoundingClientRect()是只能讀取,而element.style不僅能讀取,還能獲取。el.offsetLeft返回的距離父容器的距離,如果我們需要得到元素距離document的距離的話我們就需要這樣寫
export function offset(el) { let left = 0 let top = 0 while (el) { left -= el.offsetLeft top -= el.offsetTop el = el.offsetParent } return { left, top } }
一直找到沒有父元素的時候,就找到元素距離document的距離了
3、trigger函數在better-scroll的源碼中,多次用到trigger函數,我們來看看他都做了什么
BScroll.prototype.trigger = function (type) { let events = this._events[type] if (!events) { return } let len = events.length let eventsCopy = [...events] for (let i = 0; i < len; i++) { let event = eventsCopy[i] let [fn, context] = event if (fn) { fn.apply(context, [].slice.call(arguments,1)) } } }
trigger函數的作用就是切換到某個事件中,獲取到事件,然后使用fn進行調用。沒什么太大難度,這里想到一點能夠體現es6的優越性的地方,比如a = [1,2,3] 在es5中如果我們需要獲取a這個數組長度的時候,我們需要這樣寫
let len = a.length
但是在es6中我們不再需要這樣寫了,這樣寫就行
let { length } = a
如果需要獲取其他屬性值,就麻瓜式往里邊填。這里還涉及一個深拷貝的問題,數組和對象的深拷貝這里不做過多闡述。上述最重要的我認為就是這三個函數
總結:這個better-scroll的源碼條理清晰,畢竟滴滴D8的段位擺在那兒,非常適合閱讀。還有一些就是我對源碼分析的文章的看法。在寫這個源碼分析的文章的時候,我意識到一個問題,那就是不僅我自己能夠看懂,以前我也寫過vuex的源碼分析,基本就是把代碼全部貼上去,寫了大概2萬字,我現在覺得這種方法欠妥,正確的方式應該就是把重要的部分提取出來,最重要的引導一個思路。把代碼整個貼出來,顯得繁瑣不說,又相當于讀者自己把注釋看了一遍而已,所以我認為正確的方式是弄出一個思路,讀者嘗試讀源碼的時候,能夠有一個大概的概念。能夠自己理清思路
至于為什么這個標題不寫better-scroll的源碼分析呢,我怕有些人說有些源碼分析的文章就是垃圾,所以至少在字面上進行改變(逃。。。)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/89962.html
摘要:是一款重點解決移動端各種滾動場景需求的開源插件地址,有下列功能支持滾動列表,下拉刷新,上拉刷新,輪播圖,等功能。為了滿足這些功能,通過使用慣性滾動邊界回彈滾動條淡入淡出來確保滾動的流暢。貝瑟爾函數可以去看看,他讓動畫不再那么突兀。 BetterScroll 是一款重點解決移動端各種滾動場景需求的開源插件(GitHub地址),有下列功能支持滾動列表,下拉刷新,上拉刷新,輪播圖,slide...
摘要:函數庫動畫庫動畫庫,也是目前最通用的動畫庫。下拉框級聯選擇器移動端最好用的的篩選器組件聯動篩選移動端最好用的的篩選器組件聯動篩選顏色選擇器時間選擇器時間日期處理是一個解析,驗證,操作和顯示日期和時間的類庫。 showImg(https://segmentfault.com/img/bVbjpHt?w=900&h=383); 前言 在開發中,我們經常會將一些常用的代碼塊、功能塊進行封裝,...
閱讀 3952·2021-11-18 13:21
閱讀 4759·2021-09-27 14:01
閱讀 3110·2019-08-30 15:53
閱讀 2388·2019-08-30 15:43
閱讀 1730·2019-08-30 13:10
閱讀 1508·2019-08-29 18:39
閱讀 887·2019-08-29 15:05
閱讀 3340·2019-08-29 14:14