Files
ndm-web-platform/src/pages/vimp/components/marquee-text.vue
T

106 lines
2.2 KiB
Vue

<script setup lang="ts">
import { ref, toRefs, useTemplateRef } from 'vue';
import { useResizeObserver } from '@vueuse/core';
const props = withDefaults(
defineProps<{
text: string;
maxWidth: number;
mode?: 'swing' | 'continuous';
}>(),
{
mode: 'continuous',
},
);
const { text, maxWidth, mode } = toRefs(props);
const TEMPLATE_REF = 'marquee-text-ref';
const marqueeTextRef = useTemplateRef<HTMLDivElement>(TEMPLATE_REF);
const overflowing = ref<boolean>(false);
const scrollDistance = ref<number>(0);
const overflowDistance = ref<number>(0);
useResizeObserver(marqueeTextRef, () => {
const element = marqueeTextRef.value;
if (!element) return;
const { scrollWidth, clientWidth } = element;
overflowing.value = scrollWidth > clientWidth;
scrollDistance.value = scrollWidth;
overflowDistance.value = scrollWidth - clientWidth;
});
</script>
<template>
<div
:ref="TEMPLATE_REF"
class="marquee-text"
:style="{
maxWidth: `${maxWidth}px`,
'--scroll-distance': `${mode === 'swing' ? overflowDistance : scrollDistance}px`,
}"
>
<!-- 不溢出 -->
<div v-if="!overflowing" class="marquee-text__text">{{ text }}</div>
<!-- 来回滚动 -->
<div v-else-if="mode === 'swing'" class="marquee-text__text overflowing">{{ text }}</div>
<!-- 单向连续 -->
<div v-else class="marquee-text__scroll">
<span>{{ text }}</span>
<span class="marquee-text__gap" />
<span>{{ text }}</span>
</div>
</div>
</template>
<style scoped lang="scss">
.marquee-text {
overflow: hidden;
white-space: nowrap;
font-size: 12px;
&__text {
&.overflowing {
display: inline-block;
animation: marquee-swing 4s ease-in-out infinite;
}
}
&__scroll {
display: inline-block;
animation: marquee-continuous 3s linear infinite;
}
&__gap {
display: inline-block;
width: 24px;
}
}
@keyframes marquee-swing {
0%,
12.5% {
transform: translateX(0);
}
40%,
60% {
transform: translateX(calc(-1 * var(--scroll-distance)));
}
87.5%,
100% {
transform: translateX(0);
}
}
@keyframes marquee-continuous {
0% {
transform: translateX(0);
}
100% {
transform: translateX(calc(-1 * var(--scroll-distance) - 24px));
}
}
</style>