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

React中跨JSX文件实现点击按钮控制音乐播放器显隐

实现导航栏按钮控制跨组件音乐播放器显示隐藏的方案

因为Header和MusicPlayer属于不同组件,我们可以通过状态提升的方式,将控制播放器显示的状态放到它们的共同父组件中,再通过props传递状态和回调函数来实现交互。

步骤1:修改共同父组件(如App.js)

将播放器的显示状态维护在父组件中,同时定义切换状态的回调函数,分别传递给两个子组件:

import React, { useState } from 'react';
import Header from './Header';
import MusicPlayer from './MusicPlayer';

function App() {
  // 控制播放器显示/隐藏的状态,默认显示
  const [showPlayer, setShowPlayer] = useState(true);

  // 切换播放器显示状态的回调函数
  const togglePlayerVisibility = () => {
    setShowPlayer(prevState => !prevState);
  };

  return (
    <div className="App">
      {/* 将切换回调传给Header */}
      <Header onToggleMusic={togglePlayerVisibility} />
      {/* 将显示状态传给MusicPlayer */}
      <MusicPlayer show={showPlayer} />
      {/* 其他页面组件 */}
    </div>
  );
}

export default App;

步骤2:修改Header组件

移除组件内部的viewMusic状态,接收父组件传递的回调函数,点击音乐按钮时调用该回调:

import React from 'react'
import SunIcon from './Icons/SunIcon'
import MoonIcon from './Icons/MoonIcon'
import avatar from '../assets/avatar.jpeg'
import '../css/skeleton.css'
import '../css/normalize.css'
import '../css/components.css'
import { ThemeType } from '../ts/types';
import { BiMusic } from 'react-icons/bi'

// 接收父组件传递的onToggleMusic回调
function Header({ onToggleMusic }): JSX.Element {
  const dataTheme = document.body.getAttribute('data-theme');
  const [theme, setTheme] = React.useState<ThemeType>((): ThemeType => dataTheme === "light" ? "light" : 'dark');

  React.useEffect(() => {
    document.body.setAttribute('data-theme', theme)
  }, [theme]);

  const handleSwitchTheme = () => {
    setTheme(isDark ? 'light' : 'dark')
  }

  const isDark = theme === 'dark'

  return (
      <div className="Header container">
        <div className="ten columns Header__inner">
          <img src={avatar} alt="avatar" />
          &nbsp;&nbsp;&nbsp;
          <h2>
            <b>Sagnik. </b>
          </h2>
        </div>
        {/* 点击按钮时调用父组件的切换回调 */}
        <button className='music-btn' onClick={onToggleMusic}>
          <BiMusic fontSize="2.5rem"/>
        </button>
        <button className="switch-theme-button" onClick={handleSwitchTheme}>
          {isDark ? <SunIcon color="white" /> : <MoonIcon  />}
        </button>
      </div>
  )
}

export default Header

步骤3:修改MusicPlayer组件

移除组件内部的view状态,改用父组件传递的show属性控制渲染,同时新增逻辑:当播放器隐藏时自动暂停音乐,提升用户体验:

import React, {useState, useEffect} from 'react'
import { BiSkipPrevious, BiSkipNext, BiPause, BiPlay } from 'react-icons/bi';
import { songs } from '../assets/items';

// 接收父组件传递的show属性
export default function MusicPlayer({ show }) {
  const [isPlaying, setIsPlaying] = useState(true)
  const [isPlayAnime, setIsPlayAnime] = useState(false)
  const totalSongs = songs.length
  let songIdx = 0
  const [song, setSong] = useState({info: songs[songIdx], audioSrc: new Audio(songs[songIdx].audio)})

  // 当播放器隐藏时自动暂停音乐
  useEffect(() => {
    if (!show) {
      pauseSong();
    }
  }, [show]);

  const prevSong = () => {
    if(songIdx < 0) {
      songIdx = 0
    } else {
      songIdx = songIdx - 1
    }
    setSong({info: songs[songIdx], audioSrc: new Audio(songs[songIdx].audio)})
  }

  const nextSong = () => {
    if(songIdx > totalSongs - 1) {
      songIdx = 0
    } else {
      songIdx = songIdx + 1
    }
    setSong({info: songs[songIdx], audioSrc: new Audio(songs[songIdx].audio)})
  }

  const playSong = () => {
    setIsPlaying(false)
    setIsPlayAnime(!isPlayAnime);
    song.audioSrc.play()
  }

  const pauseSong = () => {
    setIsPlaying(true)
    setIsPlayAnime(!isPlayAnime);
    song.audioSrc.pause()
  }

  return (
      <div>
        {/* 根据父组件传递的show属性控制渲染 */}
        {show && (<div className={`music-container ${isPlayAnime ? `play` : ""}`}>
          <div className='music-wrapper'>
            <div className='music-info'>
                <h4 id='title'>{song.info.title}</h4>
            </div>
            <div className='img-container'>
                <img src={song.info.image} alt='music-cover' id='cover'/>
            </div>
            <div className='navigation'>
              <button id="prev" className='btn-prev action-btn' onClick={prevSong}>
                <BiSkipPrevious fontSize='3rem' />
              </button>
              {isPlaying === true ? (<button id="play" className='btn-play action-btn-big' onClick={playSong}>
                <BiPlay fontSize='4rem' />
              </button>) :  <button id="pause" className='btn-play action-btn-big' onClick={pauseSong}>
                <BiPause fontSize='4rem' />
              </button>
              }
              <button id="next" className='btn-next action-btn' onClick={nextSong} >
                <BiSkipNext fontSize='3rem' />
              </button>
            </div>
          </div>
        </div>)}
      </div>
  )
}

原理说明

通过将共享状态提升到共同父组件,实现了跨组件的状态同步:Header负责触发状态变更,MusicPlayer根据状态变化调整自身的显示状态,这种方式是React中处理跨组件状态交互最直接、轻量的方案。

内容的提问来源于stack exchange,提问作者Roopesh Saravanan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 15:01:01