From 995b2fba4cf8d7cddc22e0956d3260b0d5ccff2f Mon Sep 17 00:00:00 2001 From: hzj <1304805162@qq.com> Date: Sun, 4 Jan 2026 18:49:53 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=96=B0=E5=B9=B4=E6=B4=BB=E5=8A=A8):=20?= =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=BC=B9=E5=B9=95=E7=BF=BB=E8=AF=91=EF=BC=8C?= =?UTF-8?q?=E8=A1=A5=E5=85=85=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/locales/ar.json | 5 +- src/locales/en.json | 5 +- src/locales/zh.json | 5 +- .../Activities/NewYear/components/Barrage.vue | 55 ++++++++++--------- 4 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/locales/ar.json b/src/locales/ar.json index 1fef469..43b81b7 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -441,5 +441,8 @@ "Spend 50000 coins in the game ({currentValue}/{targetValue})": "أنفق 50000 عملة في اللعبة ({currentValue}/{targetValue})", "Gifts: 5 gifts({currentValue}/{targetValue})": "هدايا: 5 هدايا({currentValue}/{targetValue})", "exchange_success_coins": "تم تبادل {amount} عملة بنجاح", - "exchange_failed_coins": "فشل التبادل لـ {amount} عملة، يرجى المحاولة لاحقاً." + "exchange_failed_coins": "فشل التبادل لـ {amount} عملة، يرجى المحاولة لاحقاً.", + + "barrage_won_prize": "فاز {nickname} بـ {prizeName}", + "barrage_won_the_prize": "فاز {nickname} بـ {prizeName}" } diff --git a/src/locales/en.json b/src/locales/en.json index 36a8fe6..f402790 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -441,5 +441,8 @@ "Spend 50000 coins in the game ({currentValue}/{targetValue})": "Spend 50000 coins in the game ({currentValue}/{targetValue})", "Gifts: 5 gifts({currentValue}/{targetValue})": "Gifts: 5 gifts({currentValue}/{targetValue})", "exchange_success_coins": "Successfully exchanged {amount} coins", - "exchange_failed_coins": "Exchange failed for {amount} coins, please try again later." + "exchange_failed_coins": "Exchange failed for {amount} coins, please try again later.", + + "barrage_won_prize": "{nickname} won {prizeName}", + "barrage_won_the_prize": "{nickname} won the {prizeName}" } diff --git a/src/locales/zh.json b/src/locales/zh.json index 1a8c922..9aa0058 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -441,5 +441,8 @@ "Spend 50000 coins in the game ({currentValue}/{targetValue})": "在游戏内消费50000金币 ({currentValue}/{targetValue})", "Gifts: 5 gifts({currentValue}/{targetValue})": "礼物: 5个礼物({currentValue}/{targetValue})", "exchange_success_coins": "成功兑换 {amount} 金币", - "exchange_failed_coins": "兑换 {amount} 金币失败,请稍后重试。" + "exchange_failed_coins": "兑换 {amount} 金币失败,请稍后重试。", + + "barrage_won_prize": "{nickname} 赢得了 {prizeName}", + "barrage_won_the_prize": "{nickname} 赢得了 {prizeName}" } diff --git a/src/views/Activities/NewYear/components/Barrage.vue b/src/views/Activities/NewYear/components/Barrage.vue index 94d2af8..a0bec92 100644 --- a/src/views/Activities/NewYear/components/Barrage.vue +++ b/src/views/Activities/NewYear/components/Barrage.vue @@ -64,7 +64,7 @@ import { ref, computed, onMounted, onUnmounted, watch } from 'vue' import { useI18n } from 'vue-i18n' import { handleAvatarImageError } from '@/utils/imageHandler.js' -const { locale } = useI18n() +const { locale, t } = useI18n() const props = defineProps({ barrageList: { @@ -91,16 +91,17 @@ const props = defineProps({ const tracks = ref([[], []]) // 弹幕轨道数据 const idCounter = ref(0) // 弹幕ID计数器 -const currentIndex = ref(0) // 当前播放索引(用于循环) +const currentIndex = ref(0) // 用于取下一项弹幕的索引 // 计算实际显示的轨道(过滤空轨道) const visibleTracks = computed(() => tracks.value.filter((track) => track.length > 0)) // 显示的文本 const barrageText = (item) => { + const params = { nickname: item.nickname, prizeName: item.prizeName } return item.prizeType == 'GOLD' || item.prizeType == 'MONEY' - ? `${item.nickname} won ${item.prizeName}` - : `${item.nickname} won the ${item.prizeName}` + ? t('barrage_won_prize', params) + : t('barrage_won_the_prize', params) } // 获取弹幕样式 @@ -135,14 +136,14 @@ const getBarrageStyle = (item) => { const generateBarrageProps = (item) => { const textLength = barrageText(item).length return { - duration: Math.max(8 - textLength * 0.2, 5) * (100 / props.speed), // 弹幕项持续时间 - startPos: Math.floor(Math.random() * 21) - 10, // 弹幕项起始位置 + duration: Math.max(8 - textLength * 0.2, 5) * (100 / props.speed), // 弹幕项持续时间(每字符减少0.2秒,持续时间不低于5秒) + startPos: Math.floor(Math.random() * 21) - 10, // 弹幕项起始位置(得到-10到10之间的随机整数,避免所有弹幕都从完全相同的起点开始移动) } } // 添加弹幕到轨道 const addToTrack = (item) => { - // 寻找最短的轨道 + // 寻找最短的轨道的下标值 const trackIndex = tracks.value.reduce( (minIndex, track, index) => (track.length < tracks.value[minIndex].length ? index : minIndex), 0 @@ -151,14 +152,14 @@ const addToTrack = (item) => { if (tracks.value[trackIndex].length < props.maxItems) { tracks.value[trackIndex].push({ ...item, - id: idCounter.value++, + id: idCounter.value++, //寻找完成动画的弹幕项唯一标识 delay: Math.random() * 4, // 随机延迟(0-4秒) ...generateBarrageProps(item), }) } } -// 清理完成动画的弹幕 +// 清理完成动画的弹幕(根据动画结束状态遍历) const cleanCompleted = () => { tracks.value.forEach((track) => { for (let i = track.length - 1; i >= 0; i--) { @@ -169,7 +170,7 @@ const cleanCompleted = () => { }) } -// 弹幕动画结束处理 +// 设置弹幕动画结束状态 const handleAnimationEnd = (id) => { tracks.value.forEach((track) => { const item = track.find((item) => item.id === id) @@ -181,43 +182,45 @@ const handleAnimationEnd = (id) => { const getNextBarrage = () => { if (props.barrageList.length === 0) return null - // 循环获取弹幕 - const item = props.barrageList[currentIndex.value] - currentIndex.value = (currentIndex.value + 1) % props.barrageList.length + const item = props.barrageList[currentIndex.value] // 取得下一项弹幕项 + currentIndex.value = (currentIndex.value + 1) % props.barrageList.length //索引达到最大时则重置为0 return { ...item } // 返回副本避免污染原始数据 } // 弹幕循环逻辑 let barrageInterval = null + +// 根据设置的时间间隔自动获取下一项弹幕 const startBarrage = () => { barrageInterval = setInterval(() => { - cleanCompleted() + cleanCompleted() // 清理完成动画的弹幕 - const nextBarrage = getNextBarrage() + const nextBarrage = getNextBarrage() // 获取下一项弹幕 if (nextBarrage) { - addToTrack(nextBarrage) + addToTrack(nextBarrage) // 添加弹幕到轨道 } }, props.loopInterval) } -onMounted(startBarrage) -onUnmounted(() => clearInterval(barrageInterval)) +onMounted(() => { + startBarrage() // 开启弹幕循环 +}) + +onUnmounted(() => { + clearInterval(barrageInterval) // 清空弹幕 +}) // 监听数据源变化 watch( () => props.barrageList, (newList) => { - // 重置索引,确保重新开始循环 - currentIndex.value = 0 + currentIndex.value = 0 // 重置索引,确保重新开始循环 + clearInterval(barrageInterval) // 清空弹幕 // 如果列表为空,停止生成新弹幕 - if (newList.length === 0) { - clearInterval(barrageInterval) - } else { - // 重启弹幕循环 - clearInterval(barrageInterval) - startBarrage() + if (newList.length !== 0) { + startBarrage() // 重启弹幕循环 } }, { deep: true }