feat(components): 优化数字滚动效果并添加循环播放控制

- 在 CountTo 组件中添加 update:readyLoop 事件,用于通知数字滚动完成
- 在 Header 组件中使用 readyLoop 事件来控制 Swiper 轮播的初始化和销毁
- 优化了数字滚动的动画效果,确保滚动到目标数字后停止
This commit is contained in:
du.meimei
2025-05-28 17:22:20 +08:00
parent 70b3dc3592
commit 016d4ac4fc
2 changed files with 32 additions and 9 deletions

View File

@@ -1,5 +1,5 @@
<template> <template>
<span class="count-to">{{ formattedCount }}</span> <span class="count-to">{{ formattedCount }} </span>
</template> </template>
<script setup> <script setup>
@@ -20,6 +20,7 @@ const props = defineProps({
}, },
}) })
const emit = defineEmits(['update:readyLoop'])
// 工具函数:将 "1,000" 转成 1000 // 工具函数:将 "1,000" 转成 1000
const parseValue = (val) => { const parseValue = (val) => {
if (typeof val === 'number') return val if (typeof val === 'number') return val
@@ -42,6 +43,9 @@ const formattedCount = ref('0')
const animateCount = () => { const animateCount = () => {
parsedEnd.value = parseValue(props.end) parsedEnd.value = parseValue(props.end)
formattedCount.value = props.end
let start = 0 let start = 0
const totalSteps = Math.round(props.duration / 16) const totalSteps = Math.round(props.duration / 16)
const increment = parsedEnd.value / totalSteps const increment = parsedEnd.value / totalSteps
@@ -50,7 +54,8 @@ const animateCount = () => {
start += increment start += increment
if (start >= parsedEnd.value) { if (start >= parsedEnd.value) {
currentCount.value = parsedEnd.value currentCount.value = parsedEnd.value
formattedCount.value = props.useComma ? formatWithCommas(parsedEnd.value) : parsedEnd.value formattedCount.value = props.useComma ? formatWithCommas(parsedEnd.value) : parsedEnd.value
emit('readyLoop')
return return
} }
currentCount.value = Math.round(start) currentCount.value = Math.round(start)
@@ -71,6 +76,10 @@ watch(
() => props.end, () => props.end,
() => { () => {
animateCount() animateCount()
},
{
deep:true,
immediate:true
} }
) )
</script> </script>

View File

@@ -5,12 +5,14 @@
<!-- Swiper 轮播容器 --> <!-- Swiper 轮播容器 -->
<div class="swiper-container" ref="swiperContainer"> <div class="swiper-container" ref="swiperContainer">
<div class="swiper-wrapper"> <div class="swiper-wrapper">
<div class="banner-block swiper-slide"> <div class="banner-block swiper-slide" :key="surveyStats.user_count">
<p class="banner-block-slogan">实时链接消费者的深度洞察及日常信息采集工具</p> <p class="banner-block-slogan">实时链接消费者的深度洞察及日常信息采集工具</p>
<div class="banner-block-desc"> <div class="banner-block-desc">
已支持 <CountTo :end="surveyStats.user_count" :use-comma="true" /> 用户 | 已支持 <CountTo :end="surveyStats.user_count" :use-comma="true" :key="surveyStats.user_count"
发起 <CountTo :end="surveyStats.survey_count" :use-comma="true" /> 次调研 | @ready-loop="readyLoop"
有效回收 <CountTo :end="surveyStats.sample_count" :use-comma="true" /> 份数据 /> 用户 |
发起 <CountTo :end="surveyStats.survey_count" :use-comma="true" @ready-loop="readyLoop" /> 次调研 |
有效回收 <CountTo :end="surveyStats.sample_count" :use-comma="true" @ready-loop="readyLoop" /> 份数据
</div> </div>
</div> </div>
<!-- 动态 Banner 列表 --> <!-- 动态 Banner 列表 -->
@@ -60,7 +62,7 @@
</template> </template>
<script setup> <script setup>
import { onBeforeUnmount, onMounted, ref } from 'vue'; import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
import Swiper, { Autoplay } from 'swiper'; import Swiper, { Autoplay } from 'swiper';
import 'swiper/swiper-bundle.css'; import 'swiper/swiper-bundle.css';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
@@ -105,10 +107,22 @@ const getQuesStatics = async () => {
const res = await getQuestionnaireStatistics() const res = await getQuestionnaireStatistics()
surveyData.value = res.data surveyData.value = res.data
} }
const initSwiper = ()=>{
const readyLoop = ()=>{
if (bannerSwiper){
bannerSwiper.destroy()
}
initSwiper(true)
}
const initSwiper = (loop = false)=>{
// 初始化 Swiper // 初始化 Swiper
if (bannerSwiper) {
bannerSwiper.destroy(true, true);
bannerSwiper = null;
}
bannerSwiper = new Swiper(swiperContainer.value, { bannerSwiper = new Swiper(swiperContainer.value, {
loop: true, loop,
autoplay: { autoplay: {
delay: 5000, delay: 5000,
disableOnInteraction: false disableOnInteraction: false