Vue.js实现按钮随机播放音效:排除上次播放音效方案问询
问题
我希望实现点击按钮时随机播放音效,但需排除上次播放的音效,避免出现连续重复播放同一音效的不自然情况(从指定的5个音效中选择)。请问我的代码存在什么问题?能否提供可行的实现思路?
<template> <button class="book__nav-btn" @click="playTurnSfx"> <slot> </slot> </button> </template> <script setup> import { ref, computed, onMounted } from 'vue'; import Sfx1 from '@/assets/sounds/page-turn-1.mp3?url'; import Sfx2 from '@/assets/sounds/page-turn-2.mp3?url'; import Sfx3 from '@/assets/sounds/page-turn-3.mp3?url'; import Sfx4 from '@/assets/sounds/page-turn-4.mp3?url'; import Sfx5 from '@/assets/sounds/page-turn-5.mp3?url'; const sounds = [Sfx1, Sfx2, Sfx3, Sfx4, Sfx5]; const lastPlayedIndex = ref(null); let playableSounds = sounds.toSpliced(lastPlayedIndex.value, 1); const randomIndex = computed(() => { return Math.floor(Math.random() * playableSounds.length); }); const playTurnSfx = () => { const sound = new Audio(sounds[randomIndex.value]); sound.volume = 0.1; sound.play(); }; </script>
代码存在的问题
playableSounds未动态更新:它只在组件初始化时执行一次,且初始化时lastPlayedIndex.value为null,toSpliced(null, 1)会删除数组第一个元素,之后不会根据每次播放的结果重新生成排除上次音效的可用列表。- 索引对应错误:
randomIndex基于playableSounds的长度计算,但播放时却用该索引去取原数组sounds的元素,导致选中的音效和预期的可用音效完全不匹配。 - 未记录上次播放的索引:
playTurnSfx函数播放后没有更新lastPlayedIndex,无法为下一次播放提供排除依据。 - 响应式依赖无效:
randomIndex是计算属性,但依赖的playableSounds是普通变量而非响应式变量,即使playableSounds(理论上)更新,计算属性也不会重新计算。
可行实现思路及修正代码
核心思路:每次点击按钮时,先从音效列表中过滤掉上次播放的音效,再从剩余音效中随机选择一个,最后更新上次播放的索引。
修正后的代码:
<template> <button class="book__nav-btn" @click="playTurnSfx"> <slot> </slot> </button> </template> <script setup> import { ref } from 'vue'; import Sfx1 from '@/assets/sounds/page-turn-1.mp3?url'; import Sfx2 from '@/assets/sounds/page-turn-2.mp3?url'; import Sfx3 from '@/assets/sounds/page-turn-3.mp3?url'; import Sfx4 from '@/assets/sounds/page-turn-4.mp3?url'; import Sfx5 from '@/assets/sounds/page-turn-5.mp3?url'; const sounds = [Sfx1, Sfx2, Sfx3, Sfx4, Sfx5]; const lastPlayedIndex = ref(null); const playTurnSfx = () => { // 生成排除上次播放音效的可用列表 const availableSounds = sounds.filter((_, index) => index !== lastPlayedIndex.value); // 随机选择可用列表中的一个索引 const randomIdx = Math.floor(Math.random() * availableSounds.length); // 获取选中的音效 const selectedSound = availableSounds[randomIdx]; // 播放音效 const sound = new Audio(selectedSound); sound.volume = 0.1; sound.play().catch(err => console.error('播放失败:', err)); // 更新上次播放的索引(找到该音效在原数组中的位置) lastPlayedIndex.value = sounds.indexOf(selectedSound); }; </script>
补充说明
- 第一次播放时,
lastPlayedIndex.value为null,availableSounds就是完整的5个音效列表,正常随机选择。 - 每次播放后都会更新
lastPlayedIndex,确保下一次播放会排除当前音效。 - 添加了
play()方法的错误捕获,避免因浏览器自动播放限制等问题导致的报错。
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

