GitHub链接: https://github.com/cyjsysu/H5_video_player
上学期(2019年末)数据库大作业原本是想做一个简易的视频网站的。但上网看了一些相关内容后,当时觉得自己还不会JS无法自定义样式。于是放弃原计划,改做音乐网站。现在有了一些JS基础,所以又把以前的想法拿了出来。这篇文章相当于一份简陋的实验报告。
(小项目中用到的图标全来自百度图片)
如果在HTML中设置video的controls属性,浏览器会显示自带的相应控件。
<video controls="controls" />
一开始我以为自定义控件是通过设置controls属性来实现的。但后来我看了B站播放页面的HTML,发现B站的控件都是DIV标签。然后我才知道这些控件在HTML里是独立于video标签的,只是通过JS控制视频而已。
每次点击时根据当前视频的播放状态(Video.paused)切换到相反状态,并更改图标即可。
Video对象属性可参考https://www.runoob.com/jsref/dom-obj-video.html。这些属性在这个小项目里会用得比较多。
function playOrPause(){
var oPlayer = document.getElementById("player"); //video
let oPlayerBtn = document.getElementById("playerBtn"); //播放按钮
if(oPlayer.paused==true){
oPlayer.play();
oPlayerBtn.src="./img/pause1.png";
}else{
oPlayer.pause();
oPlayerBtn.src="./img/on1.png";
}
}
我早期看了一篇类似的博客(基本只做出了播放器控件的样子)。文章里的进度条是一个标签,导致我被误导了一段时间。后来我又是看了B站的HTML才重新找到方向。
这里自定义的进度条实际上是一个div,呈现条状是因为属性height设得很小,设置背景色即进度条。
我分别写了三个这样的div。一个为深灰色,作为进度条的背景,并在其中分别全套其他两个div。另外两个其中一个是浅灰,作为缓冲条;另一个是蓝色,作为播放进度条。另外再设一个div作为播放进度条末端的拖动按钮。
<div id="controlBar">
<div id="allBar">
<div id="bufferBar">div>
<div id="playerBar">div>
<div id="barButton">div>
div>
div>
用JS实现,在进度条上按下鼠标触发。在鼠标按下的情况下移动鼠标会使播放进度条末端和鼠标水平坐标相同(不能超出整个进度条),并通过计算更新video的currentTime属性。
因为代码中有好几处用到document.onmousemove,所以不直接绑定函数,而是使用事件监听。
function dragProgress(){
var oControlBar = document.getElementById("controlBar");
oControlBar.onmousedown = function(evt){
var e = evt || window.event;
if(e.button == 0){
leftX = getOffsetX(oControlBar);
rightX = leftX + parseInt(getComputedStyle(oControlBar)["width"]);
document.addEventListener("mousemove", toDragProgress);
}
};
document.addEventListener("mouseup", function(){
document.removeEventListener("mousemove", toDragProgress);
})
}
function toDragProgress(evt){
var e = evt || window.event;
var buttonX = e.pageX;
if(buttonX < leftX)
buttonX = leftX;
if(buttonX > rightX)
buttonX = rightX;
var prog = (buttonX - leftX) / (rightX - leftX);
// console.log(prog);
setProgress(prog);
}
用定时器实现,每秒执行一次。
function updateProgressBar() {
var oPlayer = document.getElementById("player");
var oPlayerBar = document.getElementById("playerBar");
var oBufferBar = document.getElementById("bufferBar");
var oBarButton = document.getElementById("barButton");
var oShowTime = document.getElementById("showTime");
var cTime = oPlayer.currentTime;
var dTime = oPlayer.duration;
var playerProgress = cTime / dTime * 100;
oPlayerBar.style.width = playerProgress + "%";
oBarButton.style.left = playerProgress + "%";
if (player.buffered.length){
var bTime = oPlayer.buffered.end(0);
var bufferProgress = bTime / dTime * 100;
oBufferBar.style.width = bufferProgress + "%";
}
// duration是一个全局变量
if(duration == 0)
duration = getTime(oPlayer.duration);
var currentTime = getTime(oPlayer.currentTime);
oShowTime.innerText = currentTime + "/" + duration;
}
setInterval("updateProgressBar()", 1000); //每秒
音量控制的外观也是参考着B站的效果来做的(我的没音量百分比)。
对图标设置mouseover事件。当鼠标在这个div以及子节点的div内时移除用来隐藏控制条的延时器,并显示音量条。这里要计算音量条的位置,使音量条在音量图标正上方,且不紧贴。
当鼠标移出,设置延时器,一段时间后隐藏音量条。
var hideVol = null; // 隐藏音量条事件
// 显示音量条
oControlVol.onmouseover = function(){
clearTimeout(hideVol); // 只要鼠标在音量框内就不会隐藏音量框
// 设置的音量图标和音量条是分离的,计算音量条框位置
var tarX = oControlVol.offsetLeft + (parseInt(getComputedStyle(oControlVol)["width"]) - parseInt(getComputedStyle(oVolFrame)["width"])) / 2;
var tarY = oControlVol.offsetTop - parseInt(getComputedStyle(oVolFrame)["height"]) - 20;
oVolFrame.style.left = tarX + "px";
oVolFrame.style.top = tarY + "px";
oVolFrame.style.display = "block";
};
// 隐藏音量条
oControlVol.onmouseout = function(){
hideVol = setTimeout(function () {
var oVolFrame = document.getElementById("volumeFrame");
oVolFrame.style.display = "none";
}, 600);
};
实现过程和视频进度条差不多。
可参考https://www.jianshu.com/p/54729c73686a
讲得挺全的。
对结点全屏,浏览器会显示显示自带的播放控件。这涉及到shadow DOM。在CSS文件中禁用。
video::-webkit-media-controls{
display:none !important;
}
但这不是重点。因为即使禁用了自带控件也不会显示自己的控件。
正确的做法是整个div(包括video和控件)执行全屏,上面那段css也不需要。
其实到这里很多问题实际上都是和上面重复的了。
隐藏和显示是通过控制栏的display属性实现的。鼠标移动时(document.onmousemove)显示控制栏,同时设置一个延时器来隐藏控制栏。每次触发document.onmousemove时要先移除现有的延时器。
在写这一部分时我碰到一个小坑。我设置鼠标进入控制栏时移除隐藏控制栏的延时器。但实际上仍会有延时器来隐藏控制栏。也就是说,即使鼠标在控制栏上,如果鼠标不动了,控制栏仍会被隐藏。后来发现这是因为,虽然鼠标在控制栏上时去除延时器,但当鼠标移动又会触发document.onmousemove重新设定定时器。解决方法时当鼠标进入控制栏时对document.onmousemove移除显示控制栏的函数showControl,移出时在用事件监听加回来。
document.addEventListener("mousemove", showControl);
oController.onmouseover = function(){
document.removeEventListener("mousemove", showControl);
///console.log("H");
clearTimeout(hide_control);
};
oController.onmouseout = function () {
document.addEventListener("mousemove", showControl);
}
“下一集”的功能没实现,因为项目里没考虑复杂的应用场景。但要用的时候实现也不难。