You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 07:00:24