Last active
May 9, 2023 20:10
-
-
Save iamandrewluca/5677fcb74d1215a89652c916fd3af5af to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<component :is="tag" class="relative"> | |
<button | |
:class="[ | |
'absolute top-0 h-full w-10 left-0 bg-gradient-to-r to-transparent', | |
startColor, | |
]" | |
:style="{ opacity: leftOpacity }" | |
@click="elementRef?.scrollBy({ left: -200, behavior: 'smooth' })" | |
/> | |
<div ref="elementRef" class="overflow-y-auto"> | |
<slot /> | |
</div> | |
<button | |
:class="[ | |
'absolute top-0 h-full w-10 right-0 bg-gradient-to-l to-transparent', | |
startColor, | |
]" | |
:style="{ opacity: rightOpacity }" | |
@click="elementRef?.scrollBy({ left: 200, behavior: 'smooth' })" | |
/> | |
</component> | |
</template> | |
<script setup lang="ts"> | |
import { useThrottleFn } from '@vueuse/core'; | |
import { onMounted, onUnmounted, ref } from 'vue'; | |
defineProps({ | |
tag: { | |
type: String, | |
default: 'div', | |
}, | |
startColor: { | |
type: String, | |
default: 'from-gray-200', | |
}, | |
}); | |
const resizeObserver = ref<ResizeObserver>(); | |
const elementRef = ref<HTMLElement>(); | |
const leftOpacity = ref(0); | |
const rightOpacity = ref(0); | |
const throttledAdjust = useThrottleFn(function adjust() { | |
if (!elementRef.value) return; | |
const { scrollLeft, scrollWidth, clientWidth } = elementRef.value; | |
const nonVisibleSize = scrollWidth - clientWidth; | |
const scrollPercent = Math.floor((scrollLeft * 100) / nonVisibleSize) / 100; | |
leftOpacity.value = nonVisibleSize === 0 ? 0 : scrollPercent; | |
rightOpacity.value = nonVisibleSize === 0 ? 0 : 1 - scrollPercent; | |
}, 60); | |
onMounted(() => { | |
throttledAdjust(); | |
elementRef.value?.addEventListener('scroll', throttledAdjust); | |
resizeObserver.value = new ResizeObserver(throttledAdjust); | |
resizeObserver.value?.observe(elementRef.value?.parentElement!); | |
}); | |
onUnmounted(() => { | |
elementRef.value?.removeEventListener('scroll', throttledAdjust); | |
resizeObserver.value?.disconnect(); | |
}); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment