自定义JavaScript视频播放器进度条点击事件监听失效问题排查
自定义视频播放器进度条点击事件失效问题排查与解决
问题描述
我正在使用基础JavaScript开发一款自定义视频播放器,目前除进度条点击功能外,其余所有控件均正常工作:进度条可通过timeupdate事件正常更新播放进度。但尝试添加「用户点击进度条时,视频currentTime跳转到对应位置,同时进度条同步更新」的功能时,发现为进度条绑定的click事件监听(addEventListener)完全失效,scrub函数始终未被调用。
使用Bootstrap 4框架及基础CSS样式,相关代码如下:
HTML结构
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Video Player</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> <link rel="stylesheet" href="videplayercss.css"> </head> <body> <div class="videoplayer"> <video src="yourvideo.mp4" autoplay class="videos"> </video> </div> <div class="controlplayer"> <div class="progress"> <div class="progress-bar progress-bar-animated" role="progressbar" aria-valuenow="12" aria-valuemin="0" aria-valuemax="100" style="width: 25%; margin-bottom:5%;"></div> </div> <i class="fas fa-play"></i> <input type="range" min="0" max="1" value="1" step="0.01" id="volume"> <input type="range" min="0.1" max="3" value="1" step="0.01" id="playbackspeed"> <i class="fa fa-angle-double-left backward r">10s</i> <i class="fa fa-angle-double-right forward r">25s</i> </div> <script src="videoplayerjs.js"></script> <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script> <script src="https://kit.fontawesome.com/eb0a94b8cf.js" crossorigin="anonymous"></script> </body> </html>
CSS样式
body { background-color: blueviolet } .videos { width: 50%; margin-left:20%; margin-right: 20%; margin-top:10%; } .controlplayer { display:none; width: 50%; margin-left: 20%; margin-right: 20%; background-color: ; } #volume { width: 36%; position: relative; display: inline; } #playbackspeed { width:36%; position: relative; display: inline; } .r { background-color: Transparent; border: none; cursor:pointer; width: 9%; position: relative; display: inline; }
JavaScript代码
let videoelement = document.querySelector('.videos') let pausebutton = document.querySelector('.fas'); let skipbutton = document.querySelector('.forward'); let backbutton = document.querySelector('.backward'); let speed = document.querySelector('#playbackspeed'); let vol = document.querySelector('#volume'); let controls = document.querySelector('.controlplayer') let progress = document.querySelector('.progress-bar') vol.addEventListener('change', setvol) vol.addEventListener('mousedown', setvol) function setvol(e) { videoelement.volume = vol.value; } speed.addEventListener('change', rate) speed.addEventListener('mousedown', rate) function rate(e) { videoelement.playbackRate = speed.value; } pausebutton.addEventListener('click', playing) videoelement.addEventListener('mouseenter', function () { controls.style.display = 'block'; }) videoelement.addEventListener('click', playing) videoelement.addEventListener('play', updatebutton) videoelement.addEventListener('pause', updatebutton) videoelement.addEventListener('timeupdate', handleprogress) function updatebutton() { if (videoelement.paused) { pausebutton.classList.remove('fa-pause') pausebutton.classList.add('fa-play') } else { pausebutton.classList.remove('fa-play') pausebutton.classList.add('fa-pause') } } function playing(e) { if (videoelement.paused) { videoelement.play(); videoelement.controls = null; pausebutton.classList.remove('fa-play') pausebutton.classList.add('fa-pause') } else { videoelement.pause(); pausebutton.classList.remove('fa-pause') pausebutton.classList.add('fa-play') } } skipbutton.addEventListener('click', function (e) { let t = videoelement.currentTime; if ((t + 25) < videoelement.duration) videoelement.currentTime = t + 25; else videoelement.currentTime = videoelement.duration; }) backbutton.addEventListener('click', function (e) { let t = videoelement.currentTime; if ((t - 10) >= 0) videoelement.currentTime = t - 10; else videoelement.currentTime = 0; }) function handleprogress() { let percent = (videoelement.currentTime / videoelement.duration) * 100; progress.style.width = `${percent}%`; } // 以下事件绑定完全失效,scrub函数未被调用 progress.addEventListener('click', scrub) progress.addEventListener('mousemove', scrub) function scrub(e) { console.log('sigjeg') // const scrubtime = (e.offsetX / progress.offsetWidth) * videoelement.duration; // videoelement.currentTime = scrubtime }
问题原因分析
你遇到的核心问题是事件绑定的目标元素可点击范围太小,且父容器遮挡了点击区域:
- Bootstrap的
.progress是进度条的外层容器,而你把事件绑定在内部的.progress-bar上。当视频刚开始播放时,.progress-bar的宽度很小,用户点击进度条的大部分区域其实是点击在父容器.progress上,而不是.progress-bar,所以绑定的事件根本触发不了。 - 你给
.progress-bar设置了margin-bottom:5%,这让它和父容器之间出现空隙,进一步缩小了.progress-bar的可点击范围,加剧了问题。
不修改HTML结构的解决方案
我们只需要把事件监听转移到父容器.progress上,就能捕获到整个进度条区域的点击事件,同时调整scrub函数的计算逻辑即可:
修改后的JavaScript关键代码
// 替换原来的progress事件绑定,改为绑定到父容器.progress const progressContainer = document.querySelector('.progress') progressContainer.addEventListener('click', scrub) // 优化:只有按住鼠标左键移动时才触发拖动 progressContainer.addEventListener('mousemove', function(e) { if(e.buttons === 1) { scrub(e) } }) function scrub(e) { // 基于父容器的宽度计算跳转时间,而不是.progress-bar const scrubTime = (e.offsetX / progressContainer.offsetWidth) * videoelement.duration; // 确保时间在合法范围内 videoelement.currentTime = Math.max(0, Math.min(scrubTime, videoelement.duration)); // 手动触发进度更新,让进度条即时同步(可选,timeupdate会自动触发,但手动更流畅) handleprogress(); }
补充CSS优化
移除.progress-bar的margin-bottom,让进度条和父容器完全贴合,同时给父容器添加鼠标指针样式,提升用户体验:
.progress-bar { margin-bottom: 0; /* 移除原来的margin-bottom */ } .progress { cursor: pointer; /* 提示用户进度条可点击 */ }
效果说明
修改后,点击进度条的任意位置都能触发跳转到对应播放进度,拖动鼠标时按住左键也能实时更新播放位置,完全符合需求,且不需要改动任何HTML结构。
内容的提问来源于stack exchange,提问作者Ankur
相关产品推荐
相关产品推荐

