2022-07-02 14:28:04 +02:00
|
|
|
<script lang="ts">
|
2023-04-08 02:01:42 +02:00
|
|
|
import { h, onMounted, onUnmounted, ref, watch } from "vue";
|
2022-07-02 14:28:04 +02:00
|
|
|
|
|
|
|
export default {
|
2023-04-08 02:01:42 +02:00
|
|
|
name: "MarqueeText",
|
2022-07-02 14:28:04 +02:00
|
|
|
props: {
|
|
|
|
duration: {
|
|
|
|
type: Number,
|
|
|
|
default: 15,
|
|
|
|
},
|
|
|
|
repeat: {
|
|
|
|
type: Number,
|
|
|
|
default: 2,
|
|
|
|
},
|
|
|
|
paused: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
reverse: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
setup(props) {
|
|
|
|
const contentEl = ref();
|
|
|
|
|
|
|
|
function calc() {
|
|
|
|
const eachLength = contentEl.value.offsetWidth / props.repeat;
|
|
|
|
const factor = 3000;
|
|
|
|
const duration = props.duration / ((1 / eachLength) * factor);
|
|
|
|
|
|
|
|
contentEl.value.style.animationDuration = `${duration}s`;
|
|
|
|
}
|
|
|
|
|
2022-07-02 15:07:04 +02:00
|
|
|
watch(() => props.duration, calc);
|
|
|
|
|
2022-07-02 14:28:04 +02:00
|
|
|
onMounted(() => {
|
|
|
|
calc();
|
|
|
|
});
|
|
|
|
|
2023-04-08 02:01:42 +02:00
|
|
|
onUnmounted(() => {});
|
2022-07-02 14:28:04 +02:00
|
|
|
|
|
|
|
return {
|
|
|
|
contentEl,
|
|
|
|
};
|
|
|
|
},
|
2023-04-08 02:01:42 +02:00
|
|
|
render({ $slots, $style, $props: { duration, repeat, paused, reverse } }) {
|
|
|
|
return h("div", { class: [$style.wrap] }, [
|
|
|
|
h(
|
|
|
|
"span",
|
|
|
|
{
|
|
|
|
ref: "contentEl",
|
|
|
|
class: [paused ? $style.paused : undefined, $style.content],
|
|
|
|
},
|
|
|
|
Array(repeat).fill(
|
|
|
|
h(
|
|
|
|
"span",
|
|
|
|
{
|
|
|
|
class: $style.text,
|
|
|
|
style: {
|
|
|
|
animationDirection: reverse
|
|
|
|
? "reverse"
|
|
|
|
: undefined,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
$slots.default()
|
|
|
|
)
|
|
|
|
)
|
|
|
|
),
|
2022-07-02 14:28:04 +02:00
|
|
|
]);
|
|
|
|
},
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" module>
|
|
|
|
.wrap {
|
2022-07-13 14:41:06 +02:00
|
|
|
overflow: clip;
|
2022-07-05 09:16:13 +02:00
|
|
|
animation-play-state: running;
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
animation-play-state: paused;
|
|
|
|
}
|
2022-07-02 14:28:04 +02:00
|
|
|
}
|
|
|
|
.content {
|
|
|
|
display: inline-block;
|
|
|
|
white-space: nowrap;
|
2022-07-05 09:16:13 +02:00
|
|
|
animation-play-state: inherit;
|
2022-07-02 14:28:04 +02:00
|
|
|
}
|
|
|
|
.text {
|
|
|
|
display: inline-block;
|
|
|
|
animation-name: marquee;
|
|
|
|
animation-timing-function: linear;
|
|
|
|
animation-iteration-count: infinite;
|
|
|
|
animation-duration: inherit;
|
2022-07-05 09:16:13 +02:00
|
|
|
animation-play-state: inherit;
|
2022-07-02 14:28:04 +02:00
|
|
|
}
|
|
|
|
.paused .text {
|
|
|
|
animation-play-state: paused;
|
|
|
|
}
|
|
|
|
@keyframes marquee {
|
2023-04-08 02:01:42 +02:00
|
|
|
0% {
|
|
|
|
transform: translateX(0);
|
|
|
|
}
|
|
|
|
100% {
|
|
|
|
transform: translateX(-100%);
|
|
|
|
}
|
2022-07-02 14:28:04 +02:00
|
|
|
}
|
|
|
|
</style>
|