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屬性 靜音情況是可以播放(利弊需要衡量)