HTML <video> 标签
<video src="http://nettuts.s3.amazonaws.com/763_sammyJSIntro/trailer_test.mp4" controls="controls"> 您的浏览器不支持 video 标签。 </video>
提示和注释
提示:可以在开始标签和结束标签之间放置文本内容,这样老的浏览器就可以显示出不支持该标签的信息。
当 video 标签添加上 controls 属性时,页面上会显示出所有的控制组件。若有些组件不需要只需要在css中设置相关属性把它隐藏掉即可。
<video controls></video>
//全屏按钮 video::-webkit-media-controls-fullscreen-button { display: none; } //播放按钮 video::-webkit-media-controls-play-button { display: none; } //进度条 video::-webkit-media-controls-timeline { display: none; } //观看的当前时间 video::-webkit-media-controls-current-time-display{ display: none; } //剩余时间 video::-webkit-media-controls-time-remaining-display { display: none; } //音量按钮 video::-webkit-media-controls-mute-button { display: none; } video::-webkit-media-controls-toggle-closed-captions-button { display: none; } //音量的控制条 video::-webkit-media-controls-volume-slider { display: none; } //所有控件 video::-webkit-media-controls-enclosure{ display: none; }
常用的一些 video API
"视频播放":video.play();
"视频暂停播放":video.pause();
"视频地址":video.currentSrc;
"视频总时长":video.duration;
"视频播放速率":video.playbackRate;
"是否暂停":video.paused;
"是否结束":video.ended;
"是否静音":video.muted;
"当前播放时间": video.currentTime;
"当前缓冲量":video.buffered.end(0);
"当前音量":video.volume
obj.clientWidth //获取元素的宽度
obj.clientHeight //元素的高度
obj.offsetLeft //元素相对于父元素的left
obj.offsetTop //元素相对于父元素的top
如果有 position: relative 那么父元素指向的当前
obj.offsetWidth //元素的宽度
obj.offsetHeight //元素的高度
示例效果(PC端)
已完成:暂停/播放、可拖拽播放 、上一个、下一个、全屏事件、断点续播;
未完成: 音量
↓↓↓↓↓↓ 完善断点续播↓↓↓↓↓↓
>播放资源列表
// 资源列表 var resourceList = [{ resId: 1, //资源id url: 'http://nettuts.s3.amazonaws.com/763_sammyJSIntro/trailer_test.mp4' }, { resId: 2, url: 'https://video.miaocloud.net/002ef208cc2949bba4e9439f2c3ba769/be792fd5b0c245429da6ede4a704ec08-81cec51c4b0c8d5b6cb9df02d7f94b0d-sd.mp4' } ];
>上报播放进度
function timeupdateFun(e) { var currentTime = e.target.currentTime; var duration = e.target.duration; // 如需上报播放进度---在此 // e.target.currentTime }
>拖拽计算
showTimeBox.onmousedown = function (event) { var event = event || window.event; // 距离左边距离(起始位置) var leftVal = event.clientX - this.offsetLeft; document.onmousemove = function (event) { var event = event || window.event; if (!drag) { // 是否可以拖拽 return; } barleft = event.clientX - leftVal; if (barleft <= 0) { barleft = 0; } else if (barleft >= scroll.offsetWidth - showTimeBox.offsetWidth) { barleft = scroll.offsetWidth - showTimeBox.offsetWidth; } // 进度条 var _x = barleft * 100 / (scroll.offsetWidth - showTimeBox.offsetWidth); timeBar.style.width = _x + "%"; // 时间展示区域 showTimeBox.style.left = barleft + 'px'; // 拖拽计算播放-- 根据拖拽计算播放进度 //时间拖拽计算 var updateTime = (times * _x) / 100; videoObj.currentTime = updateTime; // 时间进度条 curTime.innerHTML = getTimeStr(updateTime); //防止选择内容--当拖动鼠标过快时候,弹起鼠标,bar也会移动,修复bug window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty(); } document.onmouseup = function () { document.onmousemove = null; //弹起鼠标不做任何操作 } }
>播放上下资源
根据播放资源列表、索引ID、资源列表长度
索引idx = 资源列表.length - 1
>断点续播
根据URL地址传递资源id及播放时长 ,
playRes(); function playRes() { if (!getResId) { return; } for (var i = 0; i < resourceList.length; i++) { if (getResId == resourceList[i].resId) { document.getElementById('video').src = resourceList[i].url; document.getElementById('video').load(); // 当指定的音频/视频的元数据已加载时,会发生 loadedmetadata 事件。 document.getElementById('video').onloadedmetadata = function () { document.getElementById('video').play(); document.getElementById("playStatus").innerText = '暂停'; // 断点继播 document.getElementById('video').currentTime = getResPlayTime; } curPlayIdx = i; return; } } } // ###播放指定资源及断点续播###
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> * { margin: 0; padding: 0; } /* 去掉全屏时显示的自带控制条 */ video::-webkit-media-controls { display: none !important; } .player { width: 720px; height: 400px; margin: 0 auto; position: relative; } #video { object-fit: fill; width: 720px; height: 400px; } .control { position: relative; bottom: 0; width: 100%; display: flex; overflow: hidden; align-items: center; } .play-status { color: red; } .upPlay, .downPlay, .fullscreen { background: #000; color: #fff; margin: 0 5px; cursor: pointer; font-size: 16px; } .progress-outer { height: 10px; background-color: #ccc; margin: 0 5px; flex: 1; position: relative; border-radius: 7px; } .progress-inner { height: 10px; background-color: blue; width: 0; border-radius: 7px 0 0 7px; } .play-status { width: 40px; font-size: 18px; background-color: #333; color: #fff; } .video-timer { position: absolute; background: blue; color: #fff; left: 0%; width: 120px; text-align: center; font-size: 12px; height: 15px; line-height: 15px; /* display: flex; align-items: center; justify-content: center; */ border-radius: 7px; vertical-align: middle; cursor: pointer; top: -2px; } </style> </head> <body> <!-- http://nettuts.s3.amazonaws.com/763_sammyJSIntro/trailer_test.mp4 --> <!-- https://video.miaocloud.net/002ef208cc2949bba4e9439f2c3ba769/be792fd5b0c245429da6ede4a704ec08-81cec51c4b0c8d5b6cb9df02d7f94b0d-sd.mp4 --> <div class="player"> <video id="video" controls poster="" src="http://nettuts.s3.amazonaws.com/763_sammyJSIntro/trailer_test.mp4"></video> <div class="control"> <div class="play-status" id="playStatus">播放</div> <div class="upPlay" id="playUp">上一个</div> <div class="downPlay" id="playDown">下一个</div> <div class="fullscreen" id="fullscreen">全屏</div> <div class="progress-outer" id="scroll"> <div class="progress-inner" id="timeBar"></div> <div class="video-timer" id="showTimeBox"> <span id="currentTime">00:00</span><em>/</em> <span id="duration">00:00</span> </div> </div> </div> </div> <script> // ***以下如需要自行封装*** var videoObj = document.querySelector('video'); videoObj.addEventListener('canplay', canplayFun); videoObj.addEventListener('timeupdate', timeupdateFun); videoObj.addEventListener('loadedmetadata', onloadedmetadata); videoObj.addEventListener('play', playFun); videoObj.addEventListener('pause', pauseFun); videoObj.addEventListener('ended', endedFun); // 资源列表 var resourceList = [{ resId: 1, url: 'http://nettuts.s3.amazonaws.com/763_sammyJSIntro/trailer_test.mp4' }, { resId: 2, url: 'https://video.miaocloud.net/002ef208cc2949bba4e9439f2c3ba769/be792fd5b0c245429da6ede4a704ec08-81cec51c4b0c8d5b6cb9df02d7f94b0d-sd.mp4' } ]; // 总时长 var times = 0; // 是否拖拽快进 var drag = false; // 当前播放状态 var playStatus = document.getElementById("playStatus"); // 播放当前时间 var curTime = document.getElementById("currentTime"); // 播放总时长 var duration = document.getElementById("duration"); // 进度条移动距离 --inner var timeBar = document.getElementById("timeBar"); // 进度条总宽度 --outer var scroll = document.getElementById('scroll'); // 播放时间展示区域 var showTimeBox = document.getElementById('showTimeBox'); //数组播放资源位置 var curPlayIdx = 0; // 当前资源播放URL var curVideoURL = ''; // 播放上一个资源 var playUp = document.getElementById('playUp'); // 播放下一个资源 var playDown = document.getElementById('playDown'); // 全屏播放 var fullscreen = document.getElementById('fullscreen'); playDown.onclick = playNextFun; playUp.onclick = playUpFun; fullscreen.onclick = fullscreenFun; // ###播放指定资源及断点续播### var getResId = getQueryString('resid'); var getResPlayTime = getQueryString('playtime'); playRes(); function playRes() { if (!getResId) { return; } for (var i = 0; i < resourceList.length; i++) { if (getResId == resourceList[i].resId) { document.getElementById('video').src = resourceList[i].url; document.getElementById('video').load(); // 当指定的音频/视频的元数据已加载时,会发生 loadedmetadata 事件。 document.getElementById('video').onloadedmetadata = function () { document.getElementById('video').play(); document.getElementById("playStatus").innerText = '暂停'; // 断点继播 document.getElementById('video').currentTime = getResPlayTime; } curPlayIdx = i; return; } } } // ###播放指定资源及断点续播### //距离左边距离 var barleft = 0; showTimeBox.onmousedown = function (event) { var event = event || window.event; // 距离左边距离(起始位置) var leftVal = event.clientX - this.offsetLeft; document.onmousemove = function (event) { var event = event || window.event; if (!drag) { // 是否可以拖拽 return; } barleft = event.clientX - leftVal; if (barleft <= 0) { barleft = 0; } else if (barleft >= scroll.offsetWidth - showTimeBox.offsetWidth) { barleft = scroll.offsetWidth - showTimeBox.offsetWidth; } // 进度条 var _x = barleft * 100 / (scroll.offsetWidth - showTimeBox.offsetWidth); timeBar.style.width = _x + "%"; // 时间展示区域 showTimeBox.style.left = barleft + 'px'; // 拖拽计算播放-- 根据拖拽计算播放进度 //时间拖拽计算 var updateTime = (times * _x) / 100; videoObj.currentTime = updateTime; // 时间进度条 curTime.innerHTML = getTimeStr(updateTime); //防止选择内容--当拖动鼠标过快时候,弹起鼠标,bar也会移动,修复bug window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty(); } document.onmouseup = function () { document.onmousemove = null; //弹起鼠标不做任何操作 } } // 播放下一个资源 function playNextFun() { if (curPlayIdx >= resourceList.length - 1) { alert('最后一个资源') return; } curPlayIdx++; playListFun(curPlayIdx); } // 播放上一个资源 function playUpFun() { if (curPlayIdx <= 0) { alert('已是第一个资源'); return; } curPlayIdx--; playListFun(curPlayIdx); } // 播放资源List function playListFun(idx) { var playURL = ""; var len = resourceList.length; if (!resourceList.length) { return; } playURL = resourceList[idx].url; document.getElementById('video').src = playURL document.getElementById('video').load(); document.getElementById('video').play(); // videoObj.load(); // videoObj.play(); } // 全屏播放 function fullscreenFun() { var ele = document.getElementById('video'); if (ele.requestFullscreen) { ele.requestFullscreen(); } else if (ele.mozRequestFullScreen) { ele.mozRequestFullScreen(); } else if (ele.webkitRequestFullScreen) { ele.webkitRequestFullScreen(); } } //是否能播放 function canplayFun(e) { times = e.target.duration; // duration = times; // drag = true; //总时长 duration.innerHTML = getTimeStr(times); } function onloadedmetadata() { playStatus.onclick = function () { if (videoObj.paused || videoObj.ended) { //播放 videoObj.play(); playStatus.innerText = '暂停'; } else { //暂停 videoObj.pause(); playStatus.innerText = '播放'; } } } //更新时间 function timeupdateFun(e) { var currentTime = e.target.currentTime; var duration = e.target.duration; // 如需上报播放进度---在此 // e.target.currentTime var percent = currentTime / duration * 100; // console.log(percent) timeBar.style.width = percent + "%"; // 时间滚动区域 var _timeBoxWidth = scroll.offsetWidth - showTimeBox.offsetWidth; var x = currentTime * _timeBoxWidth / duration; // 时间进度条 showTimeBox.style.left = x + 'px'; curTime.innerHTML = getTimeStr(currentTime); } //播放 function playFun() { //监听播放 } //暂停 function pauseFun() { // 监听暂停 } //监听结束 function endedFun() { playNextFun() } //将以秒为单位的时间变成“00:00:00”格式的字符串 function getTimeStr(time) { var h = Math.floor(time / 3600); var m = Math.floor(time % 3600 / 60); var s = Math.floor(time % 60); h = h >= 10 ? h : "0" + h; m = m >= 10 ? m : "0" + m; s = s >= 10 ? s : "0" + s; return h + ":" + m + ":" + s; } function getQueryString(name) { var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i'); var r = window.location.search.substr(1).match(reg); if (r != null) { return unescape(r[2]); } return ''; } </script> </body> </html>
移动端 video/audio播放实现(功能实现,后边总结适配)
已完成: 播放/暂停 、横竖切换、拖拽播放
未完成:断点续播(同理)、资源上下切换(同理) 、
>横竖屏切换
ps:可以旋转某个Dom元素
// horizontalScreen('body');
function horizontalScreen(className) { // transform 强制横屏 var conW = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; var conH = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; $(className).css({ "transform": "rotate(90deg) translate(" + ((conH - conW) / 2) + "px," + ((conH - conW) / 2) + "px)", "width": conH + "px", "height": conW + "px", "transform-origin": "center center", "-webkit-transform-origin": "center center" }); }
>横竖屏 、拽进度条 由于(坐标方向不通做相应处理clientX \ clientY)
if(isFullScreen){ eventXY = event.clientY; }else{ eventXY = event.clientX; } barleft = eventXY - leftVal;
示例展示:
###竖屏###
###横屏###
>暂停状态时,切换横竖屏进度条异常;
如图:竖屏正常
横屏情况下:
时间区域进度条位置不正确;
原因:暂停状态没有重新计算宽及进度
timeupdateFun 函数,导致切换时长度没有计算
function timeupdateFun(e) { origCurrentTime = e.target.currentTime; origDuration = e.target.duration; var percent = origCurrentTime / origDuration * 100; // console.log(percent) timeBar.style.width = percent + "%"; // 时间滚动区域 var _timeBoxWidth = scroll.offsetWidth - showTimeBox.offsetWidth; var x = origCurrentTime * _timeBoxWidth / origDuration; // 时间进度条 showTimeBox.style.left = x + 'px'; curTime.innerHTML = getTimeStr(origCurrentTime); }
示例代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <script src="jquery-2.1.4.min.js"></script> <title>移动端Video</title> <style> * { margin: 0; padding: 0; } #video { object-fit: fill; } .video-box { position: relative; /* border: 1px solid red; */ } /* 去掉全屏时显示的自带控制条 */ /* video::-webkit-media-controls { display: none !important; } */ .control { position: absolute; bottom: 50px; left: 0; z-index: 100; width: 100%; /* padding-left: 20px; */ /* border: 1px solid yellow; */ } .progress-box{ position: absolute; bottom: 30px; left: 0; width: 100%; } .play-status { color: red; } .upPlay, .downPlay, .fullscreen { background: #000; color: #fff; margin: 0 5px; cursor: pointer; font-size: 16px; } .progress-outer { height: 10px; background-color: #ccc; margin: 0 5px; position: relative; border-radius: 7px; margin-top: 50px; } .progress-inner { height: 10px; background-color: blue; width: 0; border-radius: 7px 0 0 7px; } .play-status { width: 40px; font-size: 18px; background-color: #333; color: #fff; } .video-timer { position: absolute; background: blue; color: #fff; left: 0%; width: 120px; text-align: center; font-size: 12px; height: 15px; line-height: 15px; /* display: flex; align-items: center; justify-content: center; */ border-radius: 7px; vertical-align: middle; cursor: pointer; top: -2px; } </style> </head> <body> <div class="video-box"> <video id="video" muted src="https://video.miaocloud.net/002ef208cc2949bba4e9439f2c3ba769/be792fd5b0c245429da6ede4a704ec08-81cec51c4b0c8d5b6cb9df02d7f94b0d-sd.mp4" poster="200x200.jpg" preload="auto" autoplay x5-video-player-type="h5-page" webkit-playsinline="true" playsinline="true" x-webkit-airplay="true" style="width:100%;object-fit: cover;"> </video> <div class="control"> <span class="play-status" id="playStatus">播放</span> <span class="fullscreen" id="fullscreen">全屏</span> </div> <div class="progress-box"> <div class="progress-outer" id="scroll"> <div class="progress-inner" id="timeBar"></div> <div class="video-timer" id="showTimeBox"> <span id="currentTime">00:00:00</span><em>/</em> <span id="duration">00:00:00</span> </div> </div> </div> </div> <div> 这里是简单的文字描述 </div> <script> var isFullScreen = false; // ***以下如需要自行封装*** var videoObj = document.querySelector('video'); videoObj.addEventListener('timeupdate', timeupdateFun); videoObj.addEventListener('canplay', canplayFun); var origCurrentTime = 0; var origDuration = 0; var playStatus = document.getElementById('playStatus'); // 播放当前时间 var curTime = document.getElementById("currentTime"); // 播放总时长 var duration = document.getElementById("duration"); // 进度条移动距离 --inner var timeBar = document.getElementById("timeBar"); // 进度条总宽度 --outer var scroll = document.getElementById('scroll'); // 播放时间展示区域 var showTimeBox = document.getElementById('showTimeBox'); var times = 0; //距离左边距离 var barleft = 0; document.addEventListener("touchmove", function (e) { e.preventDefault(); }, { passive: false }); showTimeBox.ontouchstart = function (event) { var event = event.touches[0]; var eventXY = 0; // 距离左边距离(起始位置) // 横竖屏拖拽 X与Y坐标方向相反 if(isFullScreen){ eventXY = event.clientY; }else{ eventXY = event.clientX; } var leftVal = eventXY - this.offsetLeft; showTimeBox.ontouchmove = function (event) { var event = event.touches[0]; var eventXY = 0; if(isFullScreen){ eventXY = event.clientY; }else{ eventXY = event.clientX; } barleft = eventXY - leftVal; if (barleft <= 0) { barleft = 0; } else if (barleft >= scroll.offsetWidth - showTimeBox.offsetWidth) { barleft = scroll.offsetWidth - showTimeBox.offsetWidth; } console.log(barleft) // 进度条 var _x = barleft * 100 / (scroll.offsetWidth - showTimeBox.offsetWidth); timeBar.style.width = _x + "%"; // 时间展示区域 showTimeBox.style.left = barleft + 'px'; // 拖拽计算播放-- 根据拖拽计算播放进度 //时间拖拽计算 var updateTime = (times * _x) / 100; videoObj.currentTime = updateTime; videoObj.play(); // 时间进度条 curTime.innerHTML = getTimeStr(updateTime); //防止选择内容--当拖动鼠标过快时候,弹起鼠标,bar也会移动,修复bug window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty(); } document.onmouseup = function () { document.onmousemove = null; //弹起鼠标不做任何操作 } } playStatus.onclick = function () { if (videoObj.paused || videoObj.ended) { //播放 videoObj.play(); playStatus.innerText = '暂停'; } else { //暂停 videoObj.pause(); playStatus.innerText = '播放'; } } function timeupdateFun(e) { origCurrentTime = e.target.currentTime; origDuration = e.target.duration; var percent = origCurrentTime / origDuration * 100; // console.log(percent) timeBar.style.width = percent + "%"; // 时间滚动区域 var _timeBoxWidth = scroll.offsetWidth - showTimeBox.offsetWidth; var x = origCurrentTime * _timeBoxWidth / origDuration; // 时间进度条 showTimeBox.style.left = x + 'px'; curTime.innerHTML = getTimeStr(origCurrentTime); } // 切换横竖 function zoomChange(){ var percent = origCurrentTime / origDuration * 100; // console.log(percent) timeBar.style.width = percent + "%"; // 时间滚动区域 var _timeBoxWidth = scroll.offsetWidth - showTimeBox.offsetWidth; var x = origCurrentTime * _timeBoxWidth / origDuration; // 时间进度条 showTimeBox.style.left = x + 'px'; } //是否能播放 function canplayFun(e) { times = e.target.duration; // duration = times; // drag = true; //总时长 duration.innerHTML = getTimeStr(times); } fullscreen.onclick = function(){ if(isFullScreen){ $('.video-box').removeAttr('style'); }else{ horizontalScreen('.video-box'); } isFullScreen = !isFullScreen; // 重新计算进度,避免暂停切换横竖导致进度条位置不准确 zoomChange(); } function horizontalScreen(className) { // transform 强制横屏 var conW = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; var conH = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; $(className).css({ "transform": "rotate(90deg) translate(" + ((conH - conW) / 2) + "px," + ((conH - conW) / 2) + "px)", "width": conH + "px", "height": conW + "px", "transform-origin": "center center", "-webkit-transform-origin": "center center" }); } //将以秒为单位的时间变成“00:00:00”格式的字符串 function getTimeStr(time) { var h = Math.floor(time / 3600); var m = Math.floor(time % 3600 / 60); var s = Math.floor(time % 60); h = h >= 10 ? h : "0" + h; m = m >= 10 ? m : "0" + m; s = s >= 10 ? s : "0" + s; return h + ":" + m + ":" + s; } </script> </body> </html>
>问题汇总:
1、 video 标签 post无法适应video大小问题
### object-fit:fill \ cover;
### muted属性 静音情况是可以播放(利弊需要衡量)