vue前端框架vueuse的useScroll函數(shù)使用源碼分析
引言
頁面很多時候都含有可滾動視圖區(qū)域,可能是橫向滾動也可能是縱向滾動。
- 有時我們需要知道當前的滾動方向,是向左還是向右,是向上還是向下;
- 有時需要知道當前是否是正在滾動,如果滾動則顯示一個加載動畫等;
- 有時我們還需要知道滾動條是否已經(jīng)滾動到了上下左右的邊界。
如果我們自己來實現(xiàn)這一系列的邏輯判斷可能也不難,但是如何優(yōu)雅地實現(xiàn)以便于更方便地使用呢?一起研究一下vueuse的useScroll函數(shù)吧~
1.示例
vueuse官方文檔給出了useScroll函數(shù)的demo, 我們可以在線操作看一下效果:

如上圖所示,當向下滑動或者拖拽豎直方向的滾動條時則isScrolling為true表示正在向下滾動,同時useScroll能夠識別出滾動方向為向下。

如上圖所示,當滾動條觸底的時候,useScroll能夠識別出已經(jīng)到達了底部。
useScroll為何如此好用,是如何實現(xiàn)的呢?我們一同學習其源碼。
2.源碼解析
先看折疊后的代碼整體了解一下:

我們發(fā)現(xiàn)整個代碼流程包括了參數(shù)的解析,狀態(tài)的定義,滾動結(jié)束回調(diào)函數(shù),滾動監(jiān)聽處理函數(shù),最后是返回值,我們依次來看一下。
2.1 參數(shù)解析
const {
throttle = 0,
idle = 200,
onStop = noop,
onScroll = noop,
offset = {
left: 0,
right: 0,
top: 0,
bottom: 0,
},
eventListenerOptions = {
capture: false,
passive: true,
},
} = options
useScroll接受兩個參數(shù),第一參數(shù)為目標元素,也就是監(jiān)聽哪一個元素的滾動事件;第二個參數(shù)為options,涵蓋其他的選項。我們來詳細地看一下這些選項的含義:
- throttle 滾動事件的節(jié)流事件,默認不對滾動事件節(jié)流,所以throttle的默認值為0。
- idle 滾動結(jié)束時的檢查事件,這個值會和throttle 加在一起對滾動結(jié)束事件進行防抖,分析后面的代碼時會看到
- onStop 滾動結(jié)束時觸發(fā)的回調(diào)函數(shù)
- onScroll 滾動時觸發(fā)的回調(diào)函數(shù)
- offset 定義滾動條到達上下左右邊界的一個偏移值,單位為像素。例如left設置為30, 則水平滾動條距離左邊界30px時則認為到達了左邊界。
- eventListenerOptions 滾動事件監(jiān)聽器的選項
2.2 響應式狀態(tài)定義
const x = ref(0)
const y = ref(0)
const isScrolling = ref(false)
const arrivedState = reactive({
left: true,
right: false,
top: true,
bottom: false,
})
const directions = reactive({
left: false,
right: false,
top: false,
bottom: false,
})
定義響應式變量x用于記錄上次滾動的scrollLeft的值;
y記錄上次滾動的scrollTop的值;
isScrolling表示是否正在滾動。
arrivedState提供了水平方向滾動條距離左邊和右邊的距離以及垂直方向滾動條距離上邊和下邊的距離。
directions用于描述當前滾動的方向。
2.3 onScrollEnd滾動結(jié)束回調(diào)
const onScrollEnd = useDebounceFn((e: Event) => {
isScrolling.value = false
directions.left = false
directions.right = false
directions.top = false
directions.bottom = false
onStop(e)
}, throttle + idle)
滾動結(jié)束回調(diào)函數(shù)使用了useDebounceFn進行防抖。當滾動結(jié)束后,isScrolling賦值為false, 滾動方向全部賦值為false, 調(diào)用onStop回調(diào)。
2.4 onScrollHandler滾動處理
const onScrollHandler = (e: Event) => {
const eventTarget = (
e.target === document ? (e.target as Document).documentElement : e.target
) as HTMLElement
const scrollLeft = eventTarget.scrollLeft
directions.left = scrollLeft < x.value
directions.right = scrollLeft > x.value
arrivedState.left = scrollLeft <= 0 + (offset.left || 0)
arrivedState.right
= scrollLeft + eventTarget.clientWidth >= eventTarget.scrollWidth - (offset.right || 0)
x.value = scrollLeft
let scrollTop = eventTarget.scrollTop
// patch for mobile compatible
if (e.target === document && !scrollTop)
scrollTop = document.body.scrollTop
directions.top = scrollTop < y.value
directions.bottom = scrollTop > y.value
arrivedState.top = scrollTop <= 0 + (offset.top || 0)
arrivedState.bottom
= scrollTop + eventTarget.clientHeight >= eventTarget.scrollHeight - (offset.bottom || 0)
y.value = scrollTop
isScrolling.value = true
onScrollEnd(e)
onScroll(e)
}
onScrollHandler用于處理滾動。首先是水平方向滾動方向與是否到達左右邊界的判斷。說明如下:
(1)獲取當前的scrollLeft和上一次的scrollLeft也就是x.value進行比較,如果scrollLeft < x.value說明向左滾動,否則向右滾動。
(2)如何判斷是否到達左邊界?這里考慮到了偏移量offset.left。如果當前的scrollLeft <= offset.left就認為到達了左邊界。
(3)是否到達右邊界要看當前滾動的距離+元素視口的寬度(clientWidth)是否大于整個內(nèi)容的寬度(scrollWidth)減去偏移量的值(offset.right)
豎直方向的判斷同理,不再贅述,如果您不熟悉clientWidth、scrollWidth的含義,您可以閱讀筆者之前的文章:scrollTop、clientHeight、 scrollHeight...學完真的理解了。
滾動的時候還需要調(diào)用onScrollEnd觸發(fā)滾動結(jié)束事件,調(diào)用onScroll回調(diào)函數(shù),將isScrolling設置為true。

2.5 使用 useEventListener監(jiān)聽滾動事件
useEventListener( element, 'scroll', throttle ? useThrottleFn(onScrollHandler, throttle) : onScrollHandler, eventListenerOptions, )
使用useEventListener監(jiān)聽scroll事件,如果需要節(jié)流則回調(diào)函數(shù)為useThrottleFn包裝過的onScrollHandler,否則直接使用onScrollHandler。
2.6 返回值
return {
x,
y,
isScrolling,
arrivedState,
directions,
}
useScroll最后返回響應式狀態(tài)。我們使用一張圖總結(jié)一下這些狀態(tài):

3.總結(jié)
useScroll提供了響應式的滾動位置和狀態(tài)。滾動位置包括水平方向和垂直方向的滾動位置;滾動狀態(tài)包括是否在滾動,是否到達了上下左右的邊界,當前滾動的方向。useScroll使用useEventListener來監(jiān)聽滾動事件,在滾動事件的監(jiān)聽回調(diào)函數(shù)中修改狀態(tài)和位置。在其計算位置的源碼部分我們需要了解clientWidth、scrollWidth、clientHeight、scrollHeight這些值的含義。
以上就是vueuse的useScroll函數(shù)源碼分析的詳細內(nèi)容,更多關(guān)于vueuse useScroll函數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue3中是如何實現(xiàn)數(shù)據(jù)響應式示例詳解
這篇文章主要介紹了Vue3中是如何實現(xiàn)數(shù)據(jù)響應式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07
Vue?echarts@4.x中國地圖及AMap相關(guān)API使用詳解
這篇文章主要為大家介紹了Vue使用echarts@4.x中國地圖及AMap相關(guān)API使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12
如何在Vue中使localStorage具有響應式(思想實驗)
這篇文章主要介紹了如何在Vue中使localStorage具有響應式,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07
在Vue中實現(xiàn)圖表數(shù)據(jù)的動態(tài)展示的示例代碼
隨著數(shù)據(jù)可視化技術(shù)的發(fā)展,圖表在前端開發(fā)中扮演著越來越重要的角色,Vue.js 作為一個流行的前端框架,以其靈活性和易用性,成為了實現(xiàn)圖表動態(tài)展示的理想選擇,在這篇博客中,我們將學習如何在 Vue 3 中實現(xiàn)動態(tài)展示圖表數(shù)據(jù),需要的朋友可以參考下2024-11-11
如何優(yōu)雅的在一臺vps(云主機)上面部署vue+mongodb+express項目
這篇文章主要介紹了如何優(yōu)雅的在一臺vps(云主機)上面部署vue+mongodb+express項目,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01

