摘要:鎖滾動問題近日做需求,發(fā)現(xiàn)一個常用插件突然出毛病了,于是探究了一番個中原因。但在最新版下,準確的說是系統(tǒng)環(huán)境下,發(fā)生了自定義滾動條鎖滾動的問題。是通過監(jiān)聽頁面滾輪事件,進一步進行設(shè)置內(nèi)容位置來實現(xiàn)自定義滾動條的。
tinyscrollbar鎖滾動問題
近日做需求,發(fā)現(xiàn)一個常用插件jquery.tinyscrollbar突然出毛病了,于是探究了一番個中原因。
出問題的場景在ie,chrome以及其他主流瀏覽器下,jquery.tinyscrollbar能夠正常響應并滾動自定義滾動條。但在最新版firefox下,準確的說是OS X系統(tǒng)環(huán)境下,發(fā)生了自定義滾動條鎖滾動的問題。
尋找問題源頭我們發(fā)現(xiàn)場景下,是滾動了一段距離后,插件突然卡住。
于是我開始翻閱jquery.tinyscrollbar的源碼,尋找設(shè)置內(nèi)容位置的代碼。jquery.tinyscrollbar是通過監(jiān)聽頁面滾輪事件,進一步進行設(shè)置內(nèi)容位置來實現(xiàn)自定義滾動條的。其中響應滾動事件的方法是_wheel,那好,我們來看_wheel的源碼
通過閱讀jquery.tinyscrollbar源碼發(fā)現(xiàn),有一段源碼是如此陳述的:
/** * @method _wheel * @private */ function _wheel(event) { if(self.hasContentToSroll) { // Trying to make sense of all the different wheel event implementations.. // 接洽原生事件 var evntObj = event || window.event // 獲取滾輪的差量 , wheelDelta = -(evntObj.deltaY || evntObj.detail || (-1 / 3 * evntObj.wheelDelta)) / 40 // 獲取滾動單位 , multiply = (evntObj.deltaMode === 1) ? self.options.wheelSpeed : 1 ; // 計算內(nèi)容位置 self.contentPosition -= wheelDelta * multiply * self.options.wheelSpeed; self.contentPosition = Math.min((self.contentSize - self.viewportSize), Math.max(0, self.contentPosition)); // 計算滾動條位置 self.thumbPosition = self.contentPosition / self.trackRatio; /** * The move event will trigger when the carousel slides to a new slide. * 向外拋出移動事件 * @event move */ $container.trigger("move"); // 設(shè)置滾動條位置 $thumb.css(posiLabel, self.thumbPosition); // 設(shè)置內(nèi)容位置 $overview.css(posiLabel, -self.contentPosition); // 判斷是否觸底,觸底的話阻止事件繼續(xù)觸發(fā) if(self.options.wheelLock || _isAtBegin() && _isAtEnd()) { evntObj = $.event.fix(evntObj); evntObj.preventDefault(); } if(_isAtBegin() && _isAtEnd()){ evntObj.stopPropagation(); } } }
既然是內(nèi)容滾不動了,那么問題一定出在設(shè)置內(nèi)容位置的地方了
確定問題我們在這個方法里對self.contentPosition打了個log,果不其然,self.contentPosition顯示為NaN。要知道NaN和任何數(shù)做計算最后所得的值都是NaN的,所以出現(xiàn)了bug。
那么這個NaN是哪里來的呢?繼續(xù)對wheelDelta和multiply打log,發(fā)現(xiàn)wheelDelta產(chǎn)生了NaN值。
此時一頭黑人問號。近一步翻閱MDN發(fā)現(xiàn),大部分現(xiàn)代瀏覽器支持wheel事件(DOM Level 2的事件),ie和webkit瀏覽器支持mousewheel事件(非標準),老的火狐瀏覽器支持的是DOMMouseScroll事件(非標準)。于是我們開始探究幾個事件中的差異
wheel事件所具有的read-only屬性
WheelEvent.deltaX 雙精度值,表示滾輪在水平方向的差量 WheelEvent.deltaY 雙精度值,表示滾輪在豎直方向的差量 WheelEvent.deltaZ 雙精度值,表示滾輪在z軸上的差量 WheelEvent.deltaMode 無符號長整形,表示滾動的單位, 0為表示px,1為表示以行為單位滾動,2為以頁為單位滾動
wheel事件同時繼承了父類MouseEvent, UIEvent 和 Event的屬性
UIEvent.detail 返回一個長整型數(shù)值,用于描述該事件,依賴于事件類型
delta的值并不代表真實的滾動量,只是針對鼠標指針的位置來計算的
MouseWheelEvent read-only屬性
wheelDelta 長整型,以像素來計算的滾輪偏移值 wheelDeltaX 長整型,以像素來計算的滾輪x軸偏移值 wheelDeltaY 長整型,以像素來計算的滾輪y軸偏移值 detail 該值總是0,除了Opera瀏覽器以外
DOMMouseScroll只有一個屬性
detail 用于精確描述滾動,正值表示向下滾,負值表示向上滾。向上滾一頁-32768,向下滾一頁32768,其他值表示滾動行數(shù) 重要描述,該值永遠不為0
detail值的描述
在MouseWheelEvent中,
Opera設(shè)置這個值和firefox的Gecko內(nèi)核DOMMouseScroll 事件的 detail是一樣的。都用來表示以行來滾動,負值用來表示向底部或者向右滾動。在mac上,滾動加速階段會計算該值。在linux上,是由原生滾動事件設(shè)置的,值為2或者-2
所以新版firefox中wheel事件發(fā)生了啥?我們打印console.log(evt.deltaX,event.detail,event.wheelDelta)。發(fā)現(xiàn)在觸底的時候,日志顯示(0,0,undefined),真相大白!
在webkit或者blink中,deltaX這個值永遠不會被設(shè)置為0,而在新版firefox中(mac os x),這個值在某時阻尼滾動結(jié)束的時候是會變?yōu)?0。由于下式的斷言,最終整個計算中被引入了一個NaN
wheelDelta = -(evntObj.deltaY || evntObj.detail || (-1 / 3 * evntObj.wheelDelta)) / 40是插件的缺陷嗎
很明顯,插件作者最初是沒有設(shè)想到deltaY為0的情況,于是依托或運算的截斷操作寫了這句經(jīng)驗而來的代碼。對我們這些工作者而言,這樣的判斷是不嚴謹?shù)?。如果嚴格按照瀏覽器的區(qū)分來判斷,就能避免這個問題。以測試而言,明顯作者沒有考慮到undefined這樣的極端情況。
作者去哪兒啦?在git上尋找作者,發(fā)現(xiàn)該倉庫已經(jīng)年久失修了。。。作者棄坑而去
解決辦法臨時的:
自己把插件源碼改了,將默認值設(shè)為0,避免NaN引入的風險wheelDelta = -(evntObj.deltaY || evntObj.detail || (-1 / 3 * evntObj.wheelDelta)) / 40 || 0
永久的:
向火狐提issue~
可能實現(xiàn)的(極小):
向作者提pr
一切按標準或者文檔來(MSDN有時候不可信,佐證如下)
Interface :MouseWheelEvent Synchronicity :asynchronous Bubbles : yes (Though, MSDN documents "No") Target :Element, Document, Window Cancelable : yes (Though, MSDN documents "No") Default action : Scroll, moving history, or zooming in/outMDN賽高!
MDN目前已經(jīng)變成最大的web標準,文檔集散地了
參考資料MouseWheelEvent
DomMouseScrollEvent
WheelEvent
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/89367.html
摘要:下面正式推薦大神的博文前段時間使用做滾動條控件,添加滾輪事件時,查閱了一些資料,發(fā)現(xiàn)大都是文檔描述或簡單示例,對于開發(fā)者還是不夠。一測試目標探索事件中常用屬性的有效性,垂直步進算法滑動幅度以及與電腦個性化設(shè)置的關(guān)聯(lián)。 最近在用VUE寫一個后臺管理系統(tǒng),頂部標簽頁涉及鼠標滾輪事件,由于每個瀏覽器對滾輪事件的處理方式不一樣,個人對這個又不懂,折騰了很久,參考了大神的代碼,也把百度翻爛了,找...
摘要:場景當頁面出現(xiàn)浮層的時候,滑動浮層的內(nèi)容,正常情況下預期應該是浮層下邊的內(nèi)容不會滾動然而事實并非如此。當屬性的值為的時候,代表該監(jiān)聽器內(nèi)部不會調(diào)用函數(shù)來阻止默認滑動行為,瀏覽器稱這類型的監(jiān)聽器為被動監(jiān)聽器。 場景 當頁面出現(xiàn)浮層的時候,滑動浮層的內(nèi)容,正常情況下預期應該是浮層下邊的內(nèi)容不會滾動;然而事實并非如此。showImg(https://user-gold-cdn.xitu.io...
摘要:場景當頁面出現(xiàn)浮層的時候,滑動浮層的內(nèi)容,正常情況下預期應該是浮層下邊的內(nèi)容不會滾動然而事實并非如此。當屬性的值為的時候,代表該監(jiān)聽器內(nèi)部不會調(diào)用函數(shù)來阻止默認滑動行為,瀏覽器稱這類型的監(jiān)聽器為被動監(jiān)聽器。 場景 當頁面出現(xiàn)浮層的時候,滑動浮層的內(nèi)容,正常情況下預期應該是浮層下邊的內(nèi)容不會滾動;然而事實并非如此。showImg(https://user-gold-cdn.xitu.io...
閱讀 1316·2021-11-22 14:44
閱讀 2458·2021-09-30 09:47
閱讀 1225·2021-09-09 11:56
閱讀 2090·2021-09-08 09:45
閱讀 3990·2021-08-31 09:40
閱讀 1262·2019-08-30 15:52
閱讀 2051·2019-08-30 14:09
閱讀 1593·2019-08-26 17:04