React路由切换时播放器组件无法卸载问题求助
React路由切换时播放器组件正确卸载的解决方案
问题根源
player.js里直接通过document绑定DOM事件,组件卸载时没移除,导致事件残留。- 动态导入的
player.js没有封装清理逻辑,无法在组件卸载时回收资源。 - 播放器的全局事件(比如空格键)没在组件卸载时解绑,离开页面后仍生效。
- 组件卸载时没暂停视频,后台可能继续播放且占用资源。
1. 重构player.js,封装初始化和清理方法
把直接执行的代码改成模块化函数,让组件能主动控制事件绑定与解绑:
let playerElement; let playButton; let volumeInput; // 初始化播放器事件 export function initPlayer() { playerElement = document.querySelector('#Player'); playButton = document.querySelector('#play'); volumeInput = document.querySelector('#volume'); if (playButton) playButton.onclick = play; if (volumeInput) volumeInput.oninput = videoVolume; // 绑定空格键事件(对应你提到的空格键控制) document.addEventListener('keydown', handleSpaceKey); } // 清理播放器资源与事件 export function cleanupPlayer() { // 移除DOM元素事件绑定 if (playButton) playButton.onclick = null; if (volumeInput) volumeInput.oninput = null; // 移除全局空格键监听 document.removeEventListener('keydown', handleSpaceKey); // 暂停视频并重置状态 if (playerElement) { playerElement.pause(); playerElement.currentTime = 0; } } // 播放/暂停逻辑 function play() { if (!(playerElement.currentTime > 0 && !playerElement.paused && !playerElement.ended)) { playerElement.play(); } else { playerElement.pause(); } } // 音量控制逻辑 function videoVolume(e) { if (playerElement) { playerElement.volume = e.target.value / 100; } } // 空格键控制逻辑 function handleSpaceKey(e) { if (e.code === 'Space') { e.preventDefault(); play(); } }
2. 修改jsxPlayer.js,管理组件生命周期
在组件挂载时初始化播放器,卸载时执行清理:
import React from 'react'; import "./../player/player.scss"; import { initPlayer, cleanupPlayer } from "./../player/player.js"; class Player extends React.Component { constructor(props) { super(props); } componentDidMount() { // 组件挂载后初始化播放器 initPlayer(); } componentWillUnmount() { // 组件卸载时彻底清理资源 cleanupPlayer(); } render() { return ( <div> <video id="Player" src="./video.mp4"></video> <div className="timeLines"></div> <div className="playerController"> <button id="play">Play</button> <input id="volume" type="range"></input> </div> </div> ); } } export default Player;
3. 可选优化:用React Ref替代全局ID选择器
避免多次挂载时的ID冲突,更符合React组件化思想:
修改jsxPlayer.js:
import React from 'react'; import "./../player/player.scss"; import { initPlayer, cleanupPlayer } from "./../player/player.js"; class Player extends React.Component { constructor(props) { super(props); // 创建Ref绑定元素 this.playerRef = React.createRef(); this.playButtonRef = React.createRef(); this.volumeInputRef = React.createRef(); } componentDidMount() { // 把Ref传递给初始化函数 initPlayer({ player: this.playerRef.current, playButton: this.playButtonRef.current, volumeInput: this.volumeInputRef.current }); } componentWillUnmount() { cleanupPlayer(); } render() { return ( <div> <video ref={this.playerRef} src="./video.mp4"></video> <div className="timeLines"></div> <div className="playerController"> <button ref={this.playButtonRef}>Play</button> <input ref={this.volumeInputRef} type="range"></input> </div> </div> ); } } export default Player;
对应修改player.js的初始化函数:
let playerElement; let playButton; let volumeInput; export function initPlayer(refs) { playerElement = refs.player; playButton = refs.playButton; volumeInput = refs.volumeInput; if (playButton) playButton.onclick = play; if (volumeInput) volumeInput.oninput = videoVolume; document.addEventListener('keydown', handleSpaceKey); } // 其余函数保持不变...
内容的提问来源于stack exchange,提问作者Dokoa
相关产品推荐
相关产品推荐

