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里管理:
- 父组件添加状态存储当前播放的音频URL
- 给每个AudioCard传递播放函数,点击时更新父组件的状态
- 父组件里放一个唯一的
<audio>标签,根据状态切换src
不过这个方案相对复杂,如果你只是需要点击每个Card播放对应音频,方案一完全足够。
最后提醒一下:在实际项目中,最好给play()方法加上错误处理,比如捕获播放失败的情况(比如浏览器自动阻止音频播放的情况),可以用try-catch包裹:
const playsong = () => { if (audioRef.current) { try { audioRef.current.play(); } catch (error) { console.error("音频播放失败:", error); } } };
内容的提问来源于stack exchange,提问作者Nitish Kurhadkar
相关产品推荐
相关产品推荐

