feat: add scroll thumb draggable (#112)

add dependencies @vueuse/core
This commit is contained in:
Hayden
2025-02-02 19:44:44 +08:00
committed by GitHub
parent 56a2deb4eb
commit f079d8bde5
3 changed files with 89 additions and 7 deletions

View File

@@ -33,6 +33,7 @@
},
"dependencies": {
"@primevue/themes": "^4.0.7",
"@vueuse/core": "^11.3.0",
"dayjs": "^1.11.13",
"lodash": "^4.17.21",
"markdown-it": "^14.1.0",

51
pnpm-lock.yaml generated
View File

@@ -11,6 +11,9 @@ importers:
'@primevue/themes':
specifier: ^4.0.7
version: 4.0.7
'@vueuse/core':
specifier: ^11.3.0
version: 11.3.0(vue@3.5.6(typescript@5.6.2))
dayjs:
specifier: ^1.11.13
version: 1.11.13
@@ -485,6 +488,9 @@ packages:
'@types/node@22.5.5':
resolution: {integrity: sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==}
'@types/web-bluetooth@0.0.20':
resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
'@typescript-eslint/eslint-plugin@8.13.0':
resolution: {integrity: sha512-nQtBLiZYMUPkclSeC3id+x4uVd1SGtHuElTxL++SfP47jR0zfkZBJHc+gL4qPsgTuypz0k8Y2GheaDYn6Gy3rg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -601,6 +607,15 @@ packages:
'@vue/shared@3.5.6':
resolution: {integrity: sha512-eidH0HInnL39z6wAt6SFIwBrvGOpDWsDxlw3rCgo1B+CQ1781WzQUSU3YjxgdkcJo9Q8S6LmXTkvI+cLHGkQfA==}
'@vueuse/core@11.3.0':
resolution: {integrity: sha512-7OC4Rl1f9G8IT6rUfi9JrKiXy4bfmHhZ5x2Ceojy0jnd3mHNEvV4JaRygH362ror6/NZ+Nl+n13LPzGiPN8cKA==}
'@vueuse/metadata@11.3.0':
resolution: {integrity: sha512-pwDnDspTqtTo2HwfLw4Rp6yywuuBdYnPYDq+mO38ZYKGebCUQC/nVj/PXSiK9HX5otxLz8Fn7ECPbjiRz2CC3g==}
'@vueuse/shared@11.3.0':
resolution: {integrity: sha512-P8gSSWQeucH5821ek2mn/ciCk+MS/zoRKqdQIM3bHq6p7GXDAJLmnRRKmF5F65sAVJIfzQlwR3aDzwCn10s8hA==}
acorn-jsx@5.3.2:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
@@ -1668,6 +1683,17 @@ packages:
vscode-uri@3.0.8:
resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==}
vue-demi@0.14.10:
resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
engines: {node: '>=12'}
hasBin: true
peerDependencies:
'@vue/composition-api': ^1.0.0-rc.1
vue: ^3.0.0-0 || ^2.6.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
vue-eslint-parser@9.4.3:
resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==}
engines: {node: ^14.17.0 || >=16.0.0}
@@ -2009,6 +2035,8 @@ snapshots:
dependencies:
undici-types: 6.19.8
'@types/web-bluetooth@0.0.20': {}
'@typescript-eslint/eslint-plugin@8.13.0(@typescript-eslint/parser@8.13.0(eslint@9.10.0(jiti@1.21.6))(typescript@5.6.2))(eslint@9.10.0(jiti@1.21.6))(typescript@5.6.2)':
dependencies:
'@eslint-community/regexpp': 4.12.1
@@ -2181,6 +2209,25 @@ snapshots:
'@vue/shared@3.5.6': {}
'@vueuse/core@11.3.0(vue@3.5.6(typescript@5.6.2))':
dependencies:
'@types/web-bluetooth': 0.0.20
'@vueuse/metadata': 11.3.0
'@vueuse/shared': 11.3.0(vue@3.5.6(typescript@5.6.2))
vue-demi: 0.14.10(vue@3.5.6(typescript@5.6.2))
transitivePeerDependencies:
- '@vue/composition-api'
- vue
'@vueuse/metadata@11.3.0': {}
'@vueuse/shared@11.3.0(vue@3.5.6(typescript@5.6.2))':
dependencies:
vue-demi: 0.14.10(vue@3.5.6(typescript@5.6.2))
transitivePeerDependencies:
- '@vue/composition-api'
- vue
acorn-jsx@5.3.2(acorn@8.12.1):
dependencies:
acorn: 8.12.1
@@ -3180,6 +3227,10 @@ snapshots:
vscode-uri@3.0.8: {}
vue-demi@0.14.10(vue@3.5.6(typescript@5.6.2)):
dependencies:
vue: 3.5.6(typescript@5.6.2)
vue-eslint-parser@9.4.3(eslint@9.10.0(jiti@1.21.6)):
dependencies:
debug: 4.3.7

View File

@@ -23,19 +23,25 @@
</div>
</div>
<div class="absolute right-0 top-0 h-full w-2">
<div ref="scroll" class="absolute right-0 top-0 h-full w-2">
<div
ref="thumb"
:class="[
'absolute w-full cursor-pointer rounded-full bg-gray-500',
'opacity-0 transition-opacity duration-300 group-hover/scroll:opacity-30',
]"
:style="{ height: `${thumbSize}px`, top: `${thumbOffset}px` }"
:style="{
height: `${thumbSize}px`,
top: `${thumbOffset}px`,
opacity: isDragging ? '0.3' : undefined,
}"
></div>
</div>
</div>
</template>
<script setup lang="ts" generic="T">
import { useDraggable } from '@vueuse/core'
import { useContainerResize } from 'hooks/resize'
import { useContainerScroll } from 'hooks/scroll'
import { clamp } from 'lodash'
@@ -103,10 +109,34 @@ const thumbSize = computed(() => {
return Math.max(thumbHeight, 16)
})
const thumbOffset = computed(() => {
return (
(scrollY.value / (contentHeight.value - viewportHeight.value)) *
(viewportHeight.value - thumbSize.value)
)
const thumbOffset = computed({
get: () => {
return (
(scrollY.value / (contentHeight.value - viewportHeight.value)) *
(viewportHeight.value - thumbSize.value)
)
},
set: (offset) => {
scrollY.value =
(offset / (viewportHeight.value - thumbSize.value)) *
(contentHeight.value - viewportHeight.value)
},
})
const scroll = ref<HTMLElement | null>(null)
const thumb = ref<HTMLElement | null>(null)
const { isDragging } = useDraggable(thumb, {
axis: 'y',
containerElement: scroll,
onStart: () => {
document.body.style.userSelect = 'none'
},
onMove: (position) => {
thumbOffset.value = position.y
},
onEnd: () => {
document.body.style.userSelect = ''
},
})
</script>