101 lines
2.1 KiB
Vue
101 lines
2.1 KiB
Vue
<script setup>
|
|
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
|
|
|
|
const props = defineProps({
|
|
scrollTarget: { type: [String, Object], default: 'window' }
|
|
});
|
|
|
|
const scrollPosition = ref(0);
|
|
const showButton = ref(false);
|
|
let scrollContainer = null;
|
|
|
|
const onScroll = () => {
|
|
if (!scrollContainer) return;
|
|
scrollPosition.value =
|
|
typeof props.scrollTarget === 'object'
|
|
? scrollContainer.scrollTop
|
|
: window.scrollY;
|
|
};
|
|
|
|
watch(scrollPosition, (newValue) => {
|
|
showButton.value = newValue > 0;
|
|
});
|
|
|
|
const scrollToTop = () => {
|
|
if (scrollContainer) {
|
|
scrollContainer.scrollTo({ top: 0, behavior: 'smooth' });
|
|
}
|
|
};
|
|
|
|
const updateScrollContainer = (container) => {
|
|
if (container) {
|
|
if (scrollContainer) {
|
|
scrollContainer.removeEventListener('scroll', onScroll);
|
|
}
|
|
scrollContainer = container;
|
|
scrollContainer.addEventListener('scroll', onScroll);
|
|
onScroll();
|
|
}
|
|
};
|
|
|
|
defineExpose({
|
|
updateScrollContainer
|
|
});
|
|
|
|
const initScrollContainer = async () => {
|
|
await nextTick();
|
|
|
|
if (typeof props.scrollTarget === 'object') {
|
|
scrollContainer = props.scrollTarget;
|
|
} else {
|
|
scrollContainer = window;
|
|
}
|
|
|
|
if (!scrollContainer) return
|
|
scrollContainer.addEventListener('scroll', onScroll);
|
|
};
|
|
|
|
|
|
onMounted(() => {
|
|
initScrollContainer();
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
if (scrollContainer) {
|
|
scrollContainer.removeEventListener('scroll', onScroll);
|
|
scrollContainer = null;
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<QIcon
|
|
v-if="showButton"
|
|
color="primary"
|
|
name="keyboard_arrow_up"
|
|
class="scroll-to-top"
|
|
@click="scrollToTop"
|
|
>
|
|
<QTooltip>{{ $t('globals.scrollToTop') }}</QTooltip>
|
|
</QIcon>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.scroll-to-top {
|
|
position: fixed;
|
|
top: 70px;
|
|
font-size: 65px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
z-index: 1000;
|
|
transition: transform 0.2s ease-in-out;
|
|
}
|
|
|
|
.scroll-to-top:hover {
|
|
transform: translateX(-50%) scale(1.2);
|
|
cursor: pointer;
|
|
filter: brightness(0.8);
|
|
}
|
|
</style>
|
|
|