利用JS實(shí)現(xiàn)scroll自定義滾動(dòng)效果詳解
前言
最近在公司開發(fā)項(xiàng)目的時(shí)候,原生滾動(dòng)條中有些東西沒辦法自定義去精細(xì)的控制,于是開發(fā)一個(gè)類似于better-scroll一樣的瀏覽器滾動(dòng)監(jiān)聽的JS實(shí)現(xiàn),下面我們就來探究一下自定義滾動(dòng)需要考慮哪些東西,經(jīng)過哪些過程。話不多說了,來一起看看詳細(xì)的介紹吧。
選擇滾動(dòng)監(jiān)聽的事件
因?yàn)槭亲远x手機(jī)端的滾動(dòng)事件,那我選擇的是監(jiān)聽手機(jī)端的三個(gè)touch事件來實(shí)現(xiàn)監(jiān)聽,并實(shí)現(xiàn)了兩種滾動(dòng)效果,一種是通過-webkit-transform,一種是通過top屬性。兩種實(shí)現(xiàn)對(duì)于滾動(dòng)的基本效果夠能達(dá)到,可是top的不適合滾動(dòng)中還存在滾動(dòng),可是能解決滾動(dòng)中存在postion:fixed
屬性的問題;而transform可以實(shí)現(xiàn)滾動(dòng)中有滾動(dòng),可是又不能解決postion:fixed
的問題,所以,最后選擇性考慮使用哪一種實(shí)現(xiàn)方式,用法一樣。
主要的實(shí)現(xiàn)業(yè)務(wù)邏輯
handleTouchMove(event){ event.preventDefault(); this.currentY = event.targetTouches[0].screenY; this.currentTime = new Date().getTime(); // 二次及以上次數(shù)滾動(dòng)(間歇性滾動(dòng))時(shí)間和路程重置計(jì)算,0.05是間歇性滾動(dòng)的停頓位移和時(shí)間比 if (Math.abs(this.currentY - this.lastY) / Math.abs(this.currentTime - this.lastTime) < 0.05) { this.startTime = new Date().getTime(); this.resetY = this.currentY; } this.distance = this.currentY - this.startY; let temDis = this.distance + this.oldY; /*設(shè)置移動(dòng)最小值*/ temDis = temDis > this.minValue ? temDis * 1 / 3 : temDis; /*設(shè)置移動(dòng)最大值*/ temDis = temDis < -this.maxValue ? -this.maxValue + (temDis + this.maxValue) * 1 / 3 : temDis; this.$el.style["top"] = temDis + 'px'; this.lastY = this.currentY; this.lastTime = this.currentTime; this.dispatchEvent(); this.scrollFunc(event); },
代碼解讀:這是監(jiān)聽touchmove事件的回調(diào),其中主要計(jì)算出目標(biāo)節(jié)點(diǎn)this.$el
的top或者-webkit-transform中translateY的值,而計(jì)算的參考主要以事件節(jié)點(diǎn)的screenY的垂直移動(dòng)距離為參考,當(dāng)然其中還要判斷一下最大值和最小值,為了保證移動(dòng)可以的超出最大值小值一定的距離所以加了一個(gè)1/3的移動(dòng)計(jì)算。這里可能主要到了有一個(gè)間歇性滾動(dòng)的判斷和計(jì)算,主要是服務(wù)于慣性滾動(dòng)的,目的是讓慣性滾動(dòng)的值更加精確。
handleTouchEnd(event){ /*點(diǎn)透事件允許通過*/ if (!this.distance) return; event.preventDefault(); let temDis = this.distance + this.oldY; /*計(jì)算緩動(dòng)值*/ temDis = this.computeSlowMotion(temDis); /*設(shè)置最小值*/ temDis = temDis > this.minValue ? this.minValue : temDis; /*設(shè)置最大值*/ temDis = temDis < -this.maxValue ? -this.maxValue : temDis; this.$el.style["transitionDuration"] = '500ms'; this.$el.style["transitionTimingFunction"] = 'ease-out'; /*確定最終的滾動(dòng)位置*/ setTimeout(()=> { this.$el.style["top"] = temDis + 'px'; }, 0); // 判斷使用哪一種監(jiān)聽事件 if (this.slowMotionFlag) { this.dispatchEventLoop(); } else { this.dispatchEvent(); } this.$el.addEventListener('transitionend', ()=> { window.cancelAnimationFrame(this.timer); }); this.scrollFunc(event); }
代碼解讀:這是touchend事件監(jiān)聽的回調(diào),其中這里要判斷是否要攔截click和tap事件,并且這里還要計(jì)算慣性緩動(dòng)值,設(shè)置最終的最大最小值,以及設(shè)置動(dòng)畫效果和緩動(dòng)效果。下面來談一下滾性滾動(dòng)的計(jì)算:
// 計(jì)算慣性滾動(dòng)值 computeSlowMotion(temDis){ var duration = new Date().getTime() - this.startTime; // 300毫秒是判斷間隔的最佳時(shí)間 var resetDistance = this.currentY - this.resetY; if (duration < 300 && Math.abs(resetDistance) > 10) { var speed = Math.abs(resetDistance) / duration, destination; // 末速度為0 距離等于初速度的平方除以2倍加速度 destination = (speed * speed) / (2 * this.deceleration) * (resetDistance < 0 ? -1 : 1); this.slowMotionFlag = true; return temDis += destination; } else { this.slowMotionFlag = false; return temDis; } },
代碼解讀:滾性滾動(dòng)的算法主要是根據(jù)一個(gè)路程和時(shí)間計(jì)算出初速度,以及原生滾動(dòng)的加速度的大于值0.006來計(jì)算滾動(dòng)的總位移。這里主要還要判斷一下一個(gè)300ms的經(jīng)驗(yàn)值。
總結(jié)
大概的流程和思考就是這樣了,后續(xù)還會(huì)增加更多的功能進(jìn)行擴(kuò)展
附上git地址:https://github.com/yejiaming/scroll
本地下載:http://xiazai.jb51.net/201710/yuanma/js-scroll-custom(jb51.net).rar
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
JavaScript函數(shù)防抖與函數(shù)節(jié)流的定義及使用詳解
這篇文章主要為大家詳細(xì)介紹一下JavaScript中函數(shù)防抖與函數(shù)節(jié)流的定義及使用,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)JS有一定幫助,需要的可以參考一下2022-08-08ES6新特性五:Set與Map的數(shù)據(jù)結(jié)構(gòu)實(shí)例分析
這篇文章主要介紹了ES6新特性五之Set與Map的數(shù)據(jù)結(jié)構(gòu),結(jié)合實(shí)例形式分析了ES6中Set與Map的功能、定義、屬性、結(jié)構(gòu)與相關(guān)使用技巧,需要的朋友可以參考下2017-04-04javascript獲取select值的方法完整實(shí)例
這篇文章主要介紹了javascript獲取select值的方法,結(jié)合完整實(shí)例形式分析了javascript動(dòng)態(tài)遍歷與操作頁面元素相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-06-06理解JavaScript設(shè)計(jì)模式中的建造者模式
這篇文章主要介紹了理解JavaScript設(shè)計(jì)模式中的建造者模式,文章基于JavaScript的相關(guān)資料展開箱子內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-04-04詳解JS如何實(shí)現(xiàn)文字溢出時(shí)用省略號(hào)...顯示
這篇文章主要為大家詳細(xì)介紹了JavaScript如何實(shí)現(xiàn)當(dāng)文本內(nèi)容過長(zhǎng)時(shí),中間顯示省略號(hào)...,兩端正常展示,有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02