Skip to content

Commit

Permalink
feat(useScroll): new Function (vitest-dev#739)
Browse files Browse the repository at this point in the history
Co-authored-by: webfansplz <>
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
webfansplz and antfu committed Sep 17, 2021
1 parent ec310e3 commit bc6c342
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 0 deletions.
7 changes: 7 additions & 0 deletions indexes.json
Expand Up @@ -874,6 +874,13 @@
"category": "Browser",
"description": "script tag injecting"
},
{
"name": "useScroll",
"package": "core",
"docs": "https://vueuse.org/core/useScroll/",
"category": "Sensors",
"description": "reactive scroll position and state"
},
{
"name": "useSessionStorage",
"package": "core",
Expand Down
1 change: 1 addition & 0 deletions packages/core/index.ts
Expand Up @@ -58,6 +58,7 @@ export * from './useRafFn'
export * from './useRefHistory'
export * from './useResizeObserver'
export * from './useScriptTag'
export * from './useScroll'
export * from './useSessionStorage'
export * from './useShare'
export * from './useSpeechRecognition'
Expand Down
56 changes: 56 additions & 0 deletions packages/core/useScroll/demo.vue
@@ -0,0 +1,56 @@
<script setup lang="ts">
import { ref, toRefs } from 'vue-demi'
import { useScroll } from '.'
const el = ref<HTMLElement | null>(null)
const { x, y, isScrolling, arrivedState } = useScroll(el)
const { left, right, top, bottom } = toRefs(arrivedState)
</script>

<template>
<div class="flex">
<div ref="el" class="w-300px h-300px m-auto overflow-scroll bg-gray-500/5 rounded">
<div class="w-500px h-400px relative">
<div position="absolute left-0 top-0" bg="gray-500/5" p="x-2 y-1">
TopLeft
</div>
<div position="absolute left-0 bottom-0" bg="gray-500/5" p="x-2 y-1">
BottomLeft
</div>
<div position="absolute right-0 top-0" bg="gray-500/5" p="x-2 y-1">
TopRight
</div>
<div position="absolute right-0 bottom-0" bg="gray-500/5" p="x-2 y-1">
BottomRight
</div>
<div position="absolute left-1/3 top-1/3" bg="gray-500/5" p="x-2 y-1">
Scroll Me
</div>
</div>
</div>
<div class="m-auto w-280px px-6 py-4 mb-20 rounded grid grid-cols-[120px,auto] gap-2 bg-gray-500/5">
<span text="right" opacity="75">Position</span>
<div class="text-primary">
{{ x }}, {{ y }}
</div>
<span text="right" opacity="75">isScrolling</span>
<BooleanDisplay :value="isScrolling" />
<div text="right" opacity="75">
Top Arrived
</div>
<BooleanDisplay :value="top" />
<div text="right" opacity="75">
Right Arrived
</div>
<BooleanDisplay :value="right" />
<div text="right" opacity="75">
Bottom Arrived
</div>
<BooleanDisplay :value="bottom" />
<div text="right" opacity="75">
Left Arrived
</div>
<BooleanDisplay :value="left" />
</div>
</div>
</template>
22 changes: 22 additions & 0 deletions packages/core/useScroll/index.md
@@ -0,0 +1,22 @@
---
category: Sensors
---

# useScroll

Reactive scroll position and state

## Usage

```html
<script setup lang="ts">
import { useScroll } from '@vueuse/core'
const el = ref<HTMLElement | null>(null)
const { x, y, isScrolling, arrivedState } = useScroll(el)
</script>

<template>
<div ref="el"></div>
</template>
```
117 changes: 117 additions & 0 deletions packages/core/useScroll/index.ts
@@ -0,0 +1,117 @@
import { ref, reactive } from 'vue-demi'
import { useThrottleFn, useDebounceFn, noop, MaybeRef } from '@vueuse/shared'
import { useEventListener } from '../useEventListener'

export interface UseScrollOptions {
/**
* Throttle time for scroll event,it’s disabled by default.
*
* @default 0
*/
throttle?: number

/**
* The check time when scrolling ends.
* This configuration will be setting to (throttle + idle) when the `throttle` is configured.
*
* @default 200
*/
idle?: number

/**
* Trigger it when scrolling.
*
*/
onScroll?: () => void

/**
* Trigger it when scrolling ends.
*
*/
onStop?: () => void

/**
* Listener options for scroll event.
*
* @default {capture: false, passive: true}
*/
eventListenerOptions?: boolean | AddEventListenerOptions
}

/**
* Reactive scroll.
*
* @see https://vueuse.org/useScroll
* @param element
* @param options
*/

export function useScroll(
element: MaybeRef<HTMLElement | SVGElement | Window | Document>,
options: UseScrollOptions = {},
) {
const {
throttle = 0,
idle = 200,
onStop = noop,
onScroll = noop,
eventListenerOptions = {
capture: false,
passive: true,
},
}
= options

const x = ref(0)
const y = ref(0)
const isScrolling = ref(false)
const arrivedState = reactive({
left: true,
right: false,
top: true,
bottom: false,
})

if (element) {
const onScrollEnd = useDebounceFn(() => {
isScrolling.value = false
onStop()
}, throttle + idle)

const onScrollHandler = (e: Event) => {
const eventTarget = (e.target === document ? (e.target as Document).documentElement : e.target) as HTMLElement

const scrollLeft = eventTarget.scrollLeft
arrivedState.left = scrollLeft <= 0
arrivedState.right = scrollLeft + eventTarget.clientWidth >= eventTarget.scrollWidth
x.value = scrollLeft

const scrollTop = eventTarget.scrollTop
arrivedState.top = scrollTop <= 0
arrivedState.bottom = scrollTop + eventTarget.clientHeight >= eventTarget.scrollHeight
y.value = scrollTop

isScrolling.value = true
onScrollEnd()
onScroll()
}

useEventListener(
element,
'scroll',
throttle
? useThrottleFn(onScrollHandler, throttle)
: onScrollHandler,
eventListenerOptions,
)
}

return {
x,
y,
isScrolling,
arrivedState,
}
}

export type UseScrollReturn = ReturnType<typeof useScroll>
1 change: 1 addition & 0 deletions packages/functions.md
Expand Up @@ -90,6 +90,7 @@
- [`usePointer`](https://vueuse.org/core/usePointer/) — reactive [pointer state](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events)
- [`usePointerSwipe`](https://vueuse.org/core/usePointerSwipe/) — reactive swipe detection based on [PointerEvents](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent)
- [`useResizeObserver`](https://vueuse.org/core/useResizeObserver/) — reports changes to the dimensions of an Element's content or the border-box
- [`useScroll`](https://vueuse.org/core/useScroll/) — reactive scroll position and state
- [`useSpeechRecognition`](https://vueuse.org/core/useSpeechRecognition/) — reactive [SpeechRecognition](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition)
- [`useSwipe`](https://vueuse.org/core/useSwipe/) — reactive swipe detection based on [`TouchEvents`](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent)
- [`useUserMedia`](https://vueuse.org/core/useUserMedia/) — reactive [`mediaDevices.getUserMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia) streaming
Expand Down

0 comments on commit bc6c342

Please sign in to comment.