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

ReactJS中如何选中点击元素?实现音频卡片点击播放

在React中实现点击AudioCard播放对应音频的正确方式

嘿,作为React新手,你遇到的这个问题其实很典型——在React里我们不推荐像jQuery那样直接去DOM里查找元素,而是要用React提供的refs来精准访问组件内的DOM节点,这样既符合React的数据流理念,也能避免选到错误的元素。

先说说你现有代码的问题:document.querySelector("audio")会返回页面上匹配的第一个<audio>标签,所以不管你点击哪个AudioCard,播放的都是第一个音频,这显然不是你想要的效果。

下面是两种可行的解决方案,推荐第一种,更适合你的场景:

方案一:使用useRef钩子(推荐)

每个AudioCard组件都是独立的实例,我们可以给每个组件内部的<audio>标签绑定一个专属的ref,这样点击时就能直接操作当前组件内的音频元素了。

修改后的AudioCard代码如下:

import React, { useRef } from 'react'; // 引入useRef
import '../css/AudioCard.css';
import PlayArrowIcon from '@material-ui/icons/PlayArrow';

function AudioCard({ title, timestamp }) {
  // 创建一个ref来指向audio元素
  const audioRef = useRef(null);

  const playsong = () => {
    // 通过ref.current访问到当前组件内的audio元素
    if (audioRef.current) {
      audioRef.current.play();
    }
  };

  return (
    <div onClick={playsong} className="audiocard">
      <PlayArrowIcon />
      <div className="audiocard_info">
        <div className="audiocard_title">
          <h5>{title}</h5>
          {/* 将ref绑定到这个audio标签上 */}
          <audio ref={audioRef} src={require(`../sounds/${title}.mp3`)}></audio>
        </div>
      </div>
    </div>
  );
}

export default AudioCard;

为什么这个方案更好?

  • 每个AudioCard的ref都是独立的,不会和其他组件的DOM元素混淆
  • 符合React的组件封装思想,每个组件管理自己的音频播放逻辑
  • 避免了全局DOM查询带来的潜在问题

方案二:父组件统一管理播放状态(可选)

如果你希望统一控制所有音频的播放(比如播放新音频时暂停之前的),可以把音频的播放状态放到父组件RecommandedAudios里管理:

  1. 父组件添加状态存储当前播放的音频URL
  2. 给每个AudioCard传递播放函数,点击时更新父组件的状态
  3. 父组件里放一个唯一的<audio>标签,根据状态切换src

不过这个方案相对复杂,如果你只是需要点击每个Card播放对应音频,方案一完全足够。

最后提醒一下:在实际项目中,最好给play()方法加上错误处理,比如捕获播放失败的情况(比如浏览器自动阻止音频播放的情况),可以用try-catch包裹:

const playsong = () => {
  if (audioRef.current) {
    try {
      audioRef.current.play();
    } catch (error) {
      console.error("音频播放失败:", error);
    }
  }
};

内容的提问来源于stack exchange,提问作者Nitish Kurhadkar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 20:03:00