如何在Home.vue按钮点击时触发全局组件music-player的togglePlayback方法?
解决方案:跨组件触发音乐播放器方法
针对你的需求,这里提供两种适合Vue新手的实现方案,分别对应简单场景和复杂场景:
方案1:事件总线(mitt库)
适合简单的跨组件通信场景,步骤清晰易上手。
步骤1:安装mitt库
Vue3移除了原生的事件总线API,推荐使用mitt实现:
npm install mitt
步骤2:创建事件总线文件
在src/utils目录下新建eventBus.js:
import mitt from 'mitt'; const emitter = mitt(); export default emitter;
步骤3:修改music-player.vue监听事件
在组件中添加事件监听,触发现有togglePlayback方法,并在组件卸载时清理监听:
<button class="btn bg-[#a47551] hover:text-gray-50 p-3 shadow-xl" @click="togglePlayback"> <span class="material-symbols-outlined"> {{ isPlaying ? "pause" : "play_arrow" }} </span> </button> <script> import { onMounted, ref, onUnmounted } from "vue"; import emitter from '@/utils/eventBus'; // 引入事件总线 export default { setup() { const audio = new Audio(); const isPlaying = ref(false); function togglePlayback() { if (isPlaying.value) { pausePlayback(); } else { playPlayback(); } } function playPlayback() { if (!isPlaying.value) { audio.play(); isPlaying.value = true; } } function pausePlayback() { if (isPlaying.value) { audio.pause(); isPlaying.value = false; } } function handlePlaybackStart() { isPlaying.value = true; } function handlePlaybackPause() { isPlaying.value = false; } onMounted(() => { audio.src = "@/assets/song/1.mp3"; // 改用@指向src目录,路径更可靠 audio.loop = true; audio.addEventListener("play", handlePlaybackStart); audio.addEventListener("pause", handlePlaybackPause); // 监听toggle-music事件,触发togglePlayback emitter.on('toggle-music', togglePlayback); }); onUnmounted(() => { // 移除事件监听,避免内存泄漏 emitter.off('toggle-music', togglePlayback); // 清理audio事件监听 audio.removeEventListener("play", handlePlaybackStart); audio.removeEventListener("pause", handlePlaybackPause); }); return { togglePlayback, isPlaying, }; }, }; </script>
步骤4:修改Home.vue触发事件
在按钮点击方法中发送事件:
<button class="btn bg-[#a47551] text-gray-50" @click="lihatUndangan">Lihat undangan</button> <script> import { ref } from 'vue'; import { useRouter } from "vue-router"; import emitter from '@/utils/eventBus'; // 引入事件总线 export default { data() { return { namaTamu: '', isLoading: true // 补充声明isLoading,避免报错 }; }, mounted() { const namaTamu = localStorage.getItem('namaTamu'); if (!namaTamu) { const namaInput = window.prompt('Masukkan nama:'); if (namaInput && namaInput.trim() !== '') { localStorage.setItem('namaTamu', namaInput); this.namaTamu = namaInput; } else { this.namaTamu = 'Tamu Undangan'; } } else { this.namaTamu = namaTamu; } setTimeout(() => { this.isLoading = false; }, 500); }, setup() { const router = useRouter(); function lihatUndangan() { emitter.emit('toggle-music'); // 发送事件触发音乐切换 router.push('/welcome'); } return { lihatUndangan }; } }; </script>
方案2:Pinia状态管理(推荐复杂场景)
如果后续需要在多个组件中控制音乐播放状态,用Pinia管理状态更规范、可维护。
步骤1:安装Pinia
npm install pinia
步骤2:挂载Pinia到Vue应用
修改main.js:
import { createApp } from 'vue'; import { createPinia } from 'pinia'; import App from './App.vue'; const app = createApp(App); app.use(createPinia()); app.mount('#app');
步骤3:创建音乐状态仓库
在src/stores目录下新建musicStore.js:
import { defineStore } from 'pinia'; export const useMusicStore = defineStore('music', { state: () => ({ audio: new Audio(), isPlaying: false }), actions: { togglePlayback() { this.isPlaying ? this.pausePlayback() : this.playPlayback(); }, playPlayback() { if (!this.isPlaying) { this.audio.play(); this.isPlaying = true; } }, pausePlayback() { if (this.isPlaying) { this.audio.pause(); this.isPlaying = false; } }, initAudio() { this.audio.src = "@/assets/song/1.mp3"; this.audio.loop = true; // 绑定audio事件同步状态 this.audio.addEventListener("play", () => { this.isPlaying = true; }); this.audio.addEventListener("pause", () => { this.isPlaying = false; }); } } });
步骤4:重构music-player.vue使用Pinia
<button class="btn bg-[#a47551] hover:text-gray-50 p-3 shadow-xl" @click="togglePlayback"> <span class="material-symbols-outlined"> {{ isPlaying ? "pause" : "play_arrow" }} </span> </button> <script> import { onMounted } from "vue"; import { useMusicStore } from '@/stores/musicStore'; export default { setup() { const musicStore = useMusicStore(); onMounted(() => { musicStore.initAudio(); }); return { togglePlayback: musicStore.togglePlayback, isPlaying: musicStore.isPlaying, }; }, }; </script>
步骤5:修改Home.vue调用Pinia方法
<button class="btn bg-[#a47551] text-gray-50" @click="lihatUndangan">Lihat undangan</button> <script> import { ref } from 'vue'; import { useRouter } from "vue-router"; import { useMusicStore } from '@/stores/musicStore'; export default { data() { return { namaTamu: '', isLoading: true }; }, mounted() { const namaTamu = localStorage.getItem('namaTamu'); if (!namaTamu) { const namaInput = window.prompt('Masukkan nama:'); if (namaInput && namaInput.trim() !== '') { localStorage.setItem('namaTamu', namaInput); this.namaTamu = namaInput; } else { this.namaTamu = 'Tamu Undangan'; } } else { this.namaTamu = namaTamu; } setTimeout(() => { this.isLoading = false; }, 500); }, setup() { const router = useRouter(); const musicStore = useMusicStore(); function lihatUndangan() { musicStore.togglePlayback(); // 直接调用仓库方法 router.push('/welcome'); } return { lihatUndangan }; } }; </script>
额外提示
- 音频路径建议使用
@/assets/song/1.mp3,@在Vue项目中默认指向src目录,避免相对路径出错 - 使用事件总线时必须在组件卸载时移除监听,防止内存泄漏
- 如果只是简单的一次触发,事件总线足够;如果需要多组件共享播放状态,优先选Pinia
内容的提问来源于stack exchange,提问作者Mahadi Saputra
相关产品推荐
相关产品推荐

