你是否有一個夢想?用JavaScript[vue.js、react.js......]開發一款自定義配置視訊播放器
前言
沉寂了一週了,打算把這幾天的結果呈現給大家。這幾天抽空就一直在搞一個自定義視訊播放器,為什麼會有如此想法?是因為之前看一些學習視訊網站時,看到它們做的視訊播放器非常Nice!於是,就打算抽空開發一款屬於自己的視訊播放器。話不多說,一起來實戰吧!
專案展示
(這只是一張圖片哦~)
這張圖就是我們的成品,還等什麼?趕緊來實戰吧!
實戰
我會把完整原始碼放在github上,歡迎來star,地址在文末。
首先,我們會使用最原生的JavaScript來實現,老大哥肯定要打頭陣啊!
一、JavaScript
iconfont.css
:阿里字型圖示檔案,你可以在上面找到很多漂亮的圖示。index.css
:專案樣式檔案。index.js
:專案邏輯檔案。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>VamVideo(原生js版)</title>
<link rel="stylesheet" href="./css/iconfont/iconfont.css" />
<link rel="stylesheet" href="./css/index.css" />
</head>
<body>
<div class="video-box">
<video class="video-player" preload="auto" poster="./img/bg.png">
<source
src="https://mos-vod-drcn.dbankcdn.cn/P_VT/video_injection/A91343E9D/v3/9AB0A7921049102362779584128/MP4Mix_H.264_1920x1080_6000_HEAAC1_PVC_NoCut.mp4"
/>
<source />
</video>
<div class="bottom-tool">
<div class="pv-bar">
<div class="pv-played"></div>
<div class="pv-dot"></div>
</div>
<div class="pv-controls">
<div class="pc-con-l">
<div class="play-btn">
<i class="iconfont icon-bofang"></i>
<i class="iconfont icon-zanting hide"></i>
</div>
<div class="pv-time">
<span class="pv-currentTime">00:00:00</span>
<span>/</span>
<span class="pv-duration">00:00:00</span>
</div>
</div>
<div class="pc-con-r">
<div class="pv-listen ml">
<div class="pv-yl">
<p class="pv-ol"></p>
<p class="pv-bg"></p>
</div>
<div class="pv-iconyl">
<i class="iconfont icon-yinliang"></i>
<i class="iconfont icon-jingyin hide"></i>
</div>
</div>
<div class="pv-speed ml">
<p class="pv-spnum">1x</p>
<ul class="selectList">
<li>0.5x</li>
<li>1x</li>
<li>1.25x</li>
<li>1.5x</li>
<li>2x</li>
</ul>
</div>
<div class="pv-screen ml">
<i class="iconfont icon-quanping"></i>
<i class="iconfont icon-huanyuan hide"></i>
</div>
</div>
</div>
</div>
</div>
<script src="./js/index.js"></script>
</body>
</html>
我們主要看下邏輯檔案index.js
。
let timer = null;
let disX = 0;
let disL = 0;
function $(el) {
return document.querySelector(el);
}
function showEl(el) {
$(el).style.display = "block";
}
function hideEl(el) {
$(el).style.display = "none";
}
function setVp(w, h) {
$(".video-player").style.width = w + "px";
$(".video-player").style.height = h + "px";
$(".video-box").style.width = w + "px";
$(".video-box").style.height = h + "px";
$(".pv-bar").style.width = w + "px";
}
// 時間格式化
function changeTime(iNum) {
let iN = parseInt(iNum);
const iH = toZero(Math.floor(iN / 3600));
const iM = toZero(Math.floor((iN % 3600) / 60));
const iS = toZero(Math.floor(iN % 60));
return iH + ":" + iM + ":" + iS;
}
// 整0處理
function toZero(num) {
if (num <= 9) {
return "0" + num;
} else {
return "" + num;
}
}
// 底部控制欄
$(".video-box").onmouseenter = function () {
$(".bottom-tool").style.bottom = "0px";
};
$(".video-box").onmouseleave = function () {
$(".bottom-tool").style.bottom = "-45px";
};
// 倍速播放欄(顯示/隱藏)
$(".pv-spnum").onmouseover = function () {
showEl(".selectList");
};
$(".pv-controls").onmouseleave = function () {
hideEl(".selectList");
};
// 播放/暫停
$(".play-btn").onclick = function () {
if ($(".video-player").paused) {
$(".video-player").play();
hideEl(".icon-bofang");
showEl(".icon-zanting");
nowTime();
timer = setInterval(nowTime, 1000);
} else {
$(".video-player").pause();
showEl(".icon-bofang");
hideEl(".icon-zanting");
clearInterval(timer);
}
};
// 總時長
$(".video-player").oncanplay = function () {
$(".pv-duration").innerHTML = changeTime($(".video-player").duration);
};
// 播放結束
$(".video-player").onended = function (params) {
showEl(".icon-bofang");
hideEl(".icon-zanting");
};
// 播放時長
function nowTime() {
$(".pv-currentTime").innerHTML = changeTime($(".video-player").currentTime);
let scale = $(".video-player").currentTime / $(".video-player").duration;
let w = $(".pv-bar").offsetWidth - $(".pv-dot").offsetWidth;
$(".pv-dot").style.left = scale * w + "px";
$(".pv-played").style.width = scale * w + "px";
}
// 靜音/取消靜音
$(".pv-iconyl").onclick = function () {
if ($(".video-player").muted) {
$(".video-player").volume = 1;
hideEl(".icon-jingyin");
showEl(".icon-yinliang");
$(".video-player").muted = false;
} else {
$(".video-player").volume = 0;
showEl(".icon-jingyin");
hideEl(".icon-yinliang");
$(".video-player").muted = true;
}
};
let isfullScreen = false;
// 全屏
$(".pv-screen").onclick = function () {
const w = document.documentElement.clientWidth || document.body.clientWidth;
const h = document.documentElement.clientHeight || document.body.clientHeight;
isfullScreen = !isfullScreen;
if (isfullScreen) {
setVp(w, h);
hideEl(".icon-quanping");
showEl(".icon-huanyuan");
} else {
setVp(900, 480);
showEl(".icon-quanping");
hideEl(".icon-huanyuan");
}
};
// 播放進度條
$(".pv-dot").onmousedown = function (ev) {
let ev1 = ev || window.event;
disX = ev1.clientX - $(".pv-dot").offsetLeft;
document.onmousemove = function (ev) {
let ev2 = ev || window.event;
let L = ev2.clientX - disX;
if (L < 0) {
L = 0;
} else if (L > $(".pv-bar").offsetWidth - $(".pv-dot").offsetWidth) {
L = $(".pv-bar").offsetWidth - $(".pv-dot").offsetWidth;
}
$(".pv-dot").style.left = L + "px";
let scale = L / ($(".pv-bar").offsetWidth - $(".pv-dot").offsetWidth);
$(".video-player").currentTime = scale * $(".video-player").duration;
nowTime();
};
document.onmouseup = function () {
document.onmousemove = null;
};
return false;
};
// 音量控制
$(".pv-ol").onmousedown = function (ev) {
let ev1 = ev || window.event;
disL = ev1.clientX - $(".pv-ol").offsetLeft;
document.onmousemove = function (ev) {
let ev2 = ev || window.event;
let L = ev2.clientX - disL;
if (L < 0) {
L = 0;
} else if (L > $(".pv-yl").offsetWidth - $(".pv-ol").offsetWidth) {
L = $(".pv-yl").offsetWidth - $(".pv-ol").offsetWidth;
}
$(".pv-ol").style.left = L + "px";
let scale = L / ($(".pv-yl").offsetWidth - $(".pv-ol").offsetWidth);
$(".pv-bg").style.width = $(".pv-ol").offsetLeft + "px";
if ($(".pv-ol").offsetLeft !== 0) {
showEl(".icon-yinliang");
hideEl(".icon-jingyin");
} else {
showEl(".icon-jingyin");
hideEl(".icon-yinliang");
}
$(".video-player").volume = scale;
};
document.onmouseup = function () {
document.onmousemove = null;
};
return false;
};
// 播放速度
$(".selectList").onclick = function (e) {
let ev = e || window.event;
hideEl(".selectList");
$(".pv-spnum").innerText = ev.target.innerText;
const value = ev.target.innerText.replace("x", "");
$(".video-player").playbackRate = value;
};
這樣寫是可以實現一個視訊播放器,你可以通過改樣式檔案還有部分邏輯檔案來實現一個自定義配置視訊播放器,但是這種效果不太好,所以我們將通過使用Es6中的Class類來重寫這個自定義配置視訊播放器。
二、Class類
vp.js
:class類邏輯檔案。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>VamVideo(Class類版)</title>
<link rel="stylesheet" href="./css/iconfont/iconfont.css" />
<link rel="stylesheet" href="./css/index.css" />
</head>
<body>
<div class="video-box" onmouseenter="vp.bottomTup()" onmouseleave="vp.bottomTdow()">
<video class="video-player" oncanplay="vp.useOnplay()" onended="vp.useEnd()"></video>
<div class="bottom-tool">
<div class="pv-bar">
<div class="pv-played"></div>
<div class="pv-dot" onmousedown="vp.useTime()"></div>
</div>
<div class="pv-controls" onmouseleave="vp.selectListHide()">
<div class="pc-con-l">
<div class="play-btn" onclick="vp.usePlay()">
<i class="iconfont icon-bofang"></i>
<i class="iconfont icon-zanting hide"></i>
</div>
<div class="pv-time">
<span class="pv-currentTime">00:00:00</span>
<span>/</span>
<span class="pv-duration">00:00:00</span>
</div>
</div>
<div class="pc-con-r">
<div class="pv-listen ml">
<div class="pv-yl">
<p class="pv-ol" onmousedown="vp.useListen()"></p>
<p class="pv-bg"></p>
</div>
<div class="pv-iconyl" onclick="vp.useVolume()">
<i class="iconfont icon-yinliang"></i>
<i class="iconfont icon-jingyin hide"></i>
</div>
</div>
<div class="pv-speed ml">
<p class="pv-spnum" onmouseover="vp.selectListShow()">1x</p>
<ul class="selectList" onclick="vp.useSpnum()">
<li>0.5x</li>
<li>1x</li>
<li>1.25x</li>
<li>1.5x</li>
<li>2x</li>
</ul>
</div>
<div class="pv-screen ml" onclick="vp.fullScreen()">
<i class="iconfont icon-quanping"></i>
<i class="iconfont icon-huanyuan hide"></i>
</div>
</div>
</div>
</div>
</div>
<script src="./js/vp.js"></script>
<script>
const vp = new VamVideo(
document.querySelector(".video-box"), // 掛載父節點
{ // 視訊屬性
poster:"./img/bg.png",
src:"https://mos-vod-drcn.dbankcdn.cn/P_VT/video_injection/A91343E9D/v3/9AB0A7921049102362779584128/MP4Mix_H.264_1920x1080_6000_HEAAC1_PVC_NoCut.mp4",
preload:"auto",
// loop:"loop",
// autoplay:"autoplay"
},
{ // 視訊樣式
width:"1200px",
height:"600px"
}
);
</script>
</body>
</html>
看到上面的程式碼,已經發現我們可以配置視訊播放器了,那麼這個vp.js
到底是何方神聖呢?我們來看下。
class VamVideo {
constructor(vp, attrObj, styleObj) {
this.timer = null;
this.disX = 0;
this.disL = 0;
this.isfullScreen = false;
for (const key in attrObj) {
if (Object.hasOwnProperty.call(attrObj, key)) {
this.$(".video-player").setAttribute(key, attrObj[key]);
}
}
for (const key in styleObj) {
if (Object.hasOwnProperty.call(styleObj, key)) {
this.$(".video-box").style[`${key}`] = styleObj[key];
key === "width"
? (this.vbw = styleObj.width)
: (this.vbw = vp.offsetWidth);
key === "height"
? (this.vbh = styleObj.height)
: (this.vbh = vp.offsetHeight);
}
}
}
$ = (el) => document.querySelector(el);
showEl = (el) => {
this.$(el).style.display = "block";
};
hideEl = (el) => {
this.$(el).style.display = "none";
};
setVp = (w, h) => {
const _w = String(w).indexOf("px") != -1 ? w : w + "px";
const _h = String(h).indexOf("px") != -1 ? h : h + "px";
this.$(".video-player").style.width = _w;
this.$(".video-player").style.height = _h;
this.$(".video-box").style.width = _w;
this.$(".video-box").style.height = _h;
this.$(".pv-bar").style.width = _w;
};
nowTime = () => {
this.$(".pv-currentTime").innerHTML = this.changeTime(
this.$(".video-player").currentTime
);
let scale =
this.$(".video-player").currentTime / this.$(".video-player").duration;
let w = this.$(".pv-bar").offsetWidth - this.$(".pv-dot").offsetWidth;
this.$(".pv-dot").style.left = scale * w + "px";
this.$(".pv-played").style.width = scale * w + "px";
};
changeTime = (iNum) => {
let iN = parseInt(iNum);
const iH = this.toZero(Math.floor(iN / 3600));
const iM = this.toZero(Math.floor((iN % 3600) / 60));
const iS = this.toZero(Math.floor(iN % 60));
return iH + ":" + iM + ":" + iS;
};
toZero = (num) => {
if (num <= 9) {
return "0" + num;
} else {
return "" + num;
}
};
// 底部控制欄(顯示/隱藏)
bottomTup = () => {
this.$(".bottom-tool").style.bottom = "0px";
};
bottomTdow = () => {
this.$(".bottom-tool").style.bottom = "-45px";
};
// 倍速播放欄(顯示/隱藏)
selectListShow = () => {
this.showEl(".selectList");
};
selectListHide = () => {
this.hideEl(".selectList");
};
// 播放/暫停
usePlay = () => {
if (this.$(".video-player").paused) {
this.$(".video-player").play();
this.hideEl(".icon-bofang");
this.showEl(".icon-zanting");
this.nowTime();
this.timer = setInterval(this.nowTime, 1000);
} else {
this.$(".video-player").pause();
this.showEl(".icon-bofang");
this.hideEl(".icon-zanting");
clearInterval(this.timer);
}
};
// 總時長
useOnplay = () => {
this.$(".pv-duration").innerHTML = this.changeTime(
this.$(".video-player").duration
);
};
// 播放結束
useEnd = () => {
this.showEl(".icon-bofang");
this.hideEl(".icon-zanting");
};
// 靜音
useVolume = () => {
if (this.$(".video-player").muted) {
this.$(".video-player").volume = 1;
this.hideEl(".icon-jingyin");
this.showEl(".icon-yinliang");
this.$(".video-player").muted = false;
} else {
this.$(".video-player").volume = 0;
this.showEl(".icon-jingyin");
this.hideEl(".icon-yinliang");
this.$(".video-player").muted = true;
}
};
// 全屏
fullScreen = () => {
const w = document.documentElement.clientWidth || document.body.clientWidth;
const h =
document.documentElement.clientHeight || document.body.clientHeight;
this.isfullScreen = !this.isfullScreen;
if (this.isfullScreen) {
this.setVp(w, h);
this.hideEl(".icon-quanping");
this.showEl(".icon-huanyuan");
} else {
console.log("w" + this.vbw, "h" + this.vbh);
this.setVp(this.vbw, this.vbh);
this.showEl(".icon-quanping");
this.hideEl(".icon-huanyuan");
}
};
// 播放進度條
useTime = (ev) => {
let ev1 = ev || window.event;
this.disX = ev1.clientX - this.$(".pv-dot").offsetLeft;
document.onmousemove = (ev) => {
let ev2 = ev || window.event;
let L = ev2.clientX - this.disX;
if (L < 0) {
L = 0;
} else if (
L >
this.$(".pv-bar").offsetWidth - this.$(".pv-dot").offsetWidth
) {
L = this.$(".pv-bar").offsetWidth - this.$(".pv-dot").offsetWidth;
}
this.$(".pv-dot").style.left = L + "px";
let scale =
L / (this.$(".pv-bar").offsetWidth - this.$(".pv-dot").offsetWidth);
this.$(".video-player").currentTime =
scale * this.$(".video-player").duration;
this.nowTime();
};
document.onmouseup = function () {
document.onmousemove = null;
};
return false;
};
// 音量控制
useListen = (ev) => {
let ev1 = ev || window.event;
this.disL = ev1.clientX - this.$(".pv-ol").offsetLeft;
document.onmousemove = (ev) => {
let ev2 = ev || window.event;
let L = ev2.clientX - this.disL;
if (L < 0) {
L = 0;
} else if (
L >
this.$(".pv-yl").offsetWidth - this.$(".pv-ol").offsetWidth
) {
L = this.$(".pv-yl").offsetWidth - this.$(".pv-ol").offsetWidth;
}
this.$(".pv-ol").style.left = L + "px";
let scale =
L / (this.$(".pv-yl").offsetWidth - this.$(".pv-ol").offsetWidth);
this.$(".pv-bg").style.width = this.$(".pv-ol").offsetLeft + "px";
if (this.$(".pv-ol").offsetLeft !== 0) {
this.showEl(".icon-yinliang");
this.hideEl(".icon-jingyin");
} else {
this.showEl(".icon-jingyin");
this.hideEl(".icon-yinliang");
}
this.$(".video-player").volume = scale;
};
document.onmouseup = function () {
document.onmousemove = null;
};
return false;
};
// 播放速度
useSpnum = (e) => {
let ev = e || window.event;
this.hideEl(".selectList");
this.$(".pv-spnum").innerText = ev.target.innerText;
const value = ev.target.innerText.replace("x", "");
this.$(".video-player").playbackRate = value;
};
}
這樣不僅可以自定義配置一個視訊播放器,邏輯檔案中的每一個方法函式還非常的簡單明瞭,可以說是達到我們要求的目的了。但是我們可以更簡潔。
三、模板字串
strvp.js
:把標籤語句放在了模板字串中。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>VamVideo(模板字元版)</title>
<link rel="stylesheet" href="./css/iconfont/iconfont.css" />
<link rel="stylesheet" href="./css/index.css" />
</head>
<body>
<!-- 掛載點 -->
<div id="app"></div>
<script src="./js/strvp.js"></script>
<script src="./js/vp.js"></script>
<script>
const node = document.querySelector("#app");
node.insertAdjacentHTML("beforeEnd", strHtml);
const vp = new VamVideo(
document.querySelector(".video-box"), // 掛載父節點
{ // 視訊屬性
poster:"./img/bg.png",
src:"https://mos-vod-drcn.dbankcdn.cn/P_VT/video_injection/A91343E9D/v3/9AB0A7921049102362779584128/MP4Mix_H.264_1920x1080_6000_HEAAC1_PVC_NoCut.mp4",
preload:"auto",
// loop:"loop",
// autoplay:"autoplay"
},
{ // 視訊樣式
width:"1200px",
height:"600px"
}
);
</script>
</body>
</html>
可以看到上面的程式碼,我直接把標籤語句轉換為字串直接掛載到父節點上,這樣就更加簡潔了。下面的程式碼就是一堆標籤語句。
const strHtml = `
<div class="video-box" οnmοuseenter="vp.bottomTup()" οnmοuseleave="vp.bottomTdow()">
<video class="video-player" οncanplay="vp.useOnplay()" οnended="vp.useEnd()"></video>
<div class="bottom-tool">
<div class="pv-bar">
<div class="pv-played"></div>
<div class="pv-dot" οnmοusedοwn="vp.useTime()"></div>
</div>
<div class="pv-controls" οnmοuseleave="vp.selectListHide()">
<div class="pc-con-l">
<div class="play-btn" οnclick="vp.usePlay()">
<i class="iconfont icon-bofang"></i>
<i class="iconfont icon-zanting hide"></i>
</div>
<div class="pv-time">
<span class="pv-currentTime">00:00:00</span>
<span>/</span>
<span class="pv-duration">00:00:00</span>
</div>
</div>
<div class="pc-con-r">
<div class="pv-listen ml">
<div class="pv-yl">
<p class="pv-ol" οnmοusedοwn="vp.useListen()"></p>
<p class="pv-bg"></p>
</div>
<div class="pv-iconyl" οnclick="vp.useVolume()">
<i class="iconfont icon-yinliang"></i>
<i class="iconfont icon-jingyin hide"></i>
</div>
</div>
<div class="pv-speed ml">
<p class="pv-spnum" οnmοuseοver="vp.selectListShow()">1x</p>
<ul class="selectList" οnclick="vp.useSpnum()">
<li>0.5x</li>
<li>1x</li>
<li>1.25x</li>
<li>1.5x</li>
<li>2x</li>
</ul>
</div>
<div class="pv-screen ml" οnclick="vp.fullScreen()">
<i class="iconfont icon-quanping"></i>
<i class="iconfont icon-huanyuan hide"></i>
</div>
</div>
</div>
</div>
</div>
`;
我們再進一步,使用Vue.js、React.js分別實現一波。
四、Vue.js
vue@2.6.12
:引入Vue.js,這裡我們使用@2.6.12。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>VamVideo(Vue.js版)</title>
<link rel="stylesheet" href="./css/iconfont/iconfont.css" />
<link rel="stylesheet" href="./css/index.css" />
</head>
<body>
<div id="app">
<vam-video></vam-video>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
<script src="./js/vp.js"></script>
<script>
Vue.component("vam-video", {
template: `
<div class="video-box" @mouseenter="vp.bottomTup()" @mouseleave="vp.bottomTdow()">
<video class="video-player" @canplay="vp.useOnplay()" @ended="vp.useEnd()"></video>
<div class="bottom-tool">
<div class="pv-bar">
<div class="pv-played"></div>
<div class="pv-dot" @mousedown="vp.useTime()"></div>
</div>
<div class="pv-controls" @mouseleave="vp.selectListHide()">
<div class="pc-con-l">
<div class="play-btn" @click="vp.usePlay()">
<i class="iconfont icon-bofang"></i>
<i class="iconfont icon-zanting hide"></i>
</div>
<div class="pv-time">
<span class="pv-currentTime">00:00:00</span>
<span>/</span>
<span class="pv-duration">00:00:00</span>
</div>
</div>
<div class="pc-con-r">
<div class="pv-listen ml">
<div class="pv-yl">
<p class="pv-ol" @mousedown="vp.useListen()"></p>
<p class="pv-bg"></p>
</div>
<div class="pv-iconyl" @click="vp.useVolume()">
<i class="iconfont icon-yinliang"></i>
<i class="iconfont icon-jingyin hide"></i>
</div>
</div>
<div class="pv-speed ml">
<p class="pv-spnum" @mouseover="vp.selectListShow()">1x</p>
<ul class="selectList" @click="vp.useSpnum()">
<li>0.5x</li>
<li>1x</li>
<li>1.25x</li>
<li>1.5x</li>
<li>2x</li>
</ul>
</div>
<div class="pv-screen ml" @click="vp.fullScreen()">
<i class="iconfont icon-quanping"></i>
<i class="iconfont icon-huanyuan hide"></i>
</div>
</div>
</div>
</div>
</div>
`,
});
const vm = new Vue({
el: "#app",
});
const vp = new VamVideo(
document.querySelector(".video-box"), // 掛載父節點
{
// 視訊屬性
poster: "./img/bg.png",
src:
"https://mos-vod-drcn.dbankcdn.cn/P_VT/video_injection/A91343E9D/v3/9AB0A7921049102362779584128/MP4Mix_H.264_1920x1080_6000_HEAAC1_PVC_NoCut.mp4",
preload: "auto",
// loop:"loop",
// autoplay:"autoplay"
},
{
// 視訊樣式
width: "1200px",
height: "600px",
}
);
</script>
</body>
</html>
從上面的程式碼中可以看到,可以直接在全域性例項化一個物件,可以根據自己的需要進行配置。
五、React.js
react.development.js
- React 的核心庫。react-dom.development
- 提供與 DOM 相關的功能。babel.min.js
- Babel 可以將 ES6 程式碼轉為 ES5 程式碼,這樣我們就能在目前不支援 ES6 瀏覽器上執行 React 程式碼。Babel 內嵌了對 JSX 的支援。通過將 Babel 和 babel-sublime 包(package)一同使用可以讓原始碼的語法渲染上升到一個全新的水平。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>VamVideo(React.js版)</title>
<link rel="stylesheet" href="./css/iconfont/iconfont.css" />
<link rel="stylesheet" href="./css/index.css" />
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="app"></div>
<script src="./js/vp.js"></script>
<script type="text/babel">
class VamVideoPlayer extends React.Component {
constructor(props) {
super(props);
this.vper = null;
}
vp(v) {
this.vper = v;
}
componentDidMount() {
let vps = new VamVideo(
document.querySelector(".video-box"), // 掛載父節點
{
// 視訊屬性
poster: "./img/bg.png",
src:
"https://mos-vod-drcn.dbankcdn.cn/P_VT/video_injection/A91343E9D/v3/9AB0A7921049102362779584128/MP4Mix_H.264_1920x1080_6000_HEAAC1_PVC_NoCut.mp4",
preload: "auto",
// loop:"loop",
// autoplay:"autoplay"
},
{
// 視訊樣式
width: "1200px",
height: "600px",
}
);
this.vp(vps);
}
render() {
return (
<div
className="video-box"
onMouseEnter={() => this.vper.bottomTup()}
onMouseLeave={() => this.vper.bottomTdow()}
>
<video
className="video-player"
onCanPlay={() => this.vper.useOnplay()}
onEnded={() => this.vper.useEnd()}
></video>
<div className="bottom-tool">
<div className="pv-bar">
<div className="pv-played"></div>
<div
className="pv-dot"
onMouseDown={(e) => this.vper.useTime(e)}
></div>
</div>
<div
className="pv-controls"
onMouseLeave={() => this.vper.selectListHide()}
>
<div className="pc-con-l">
<div
className="play-btn"
onClick={() => this.vper.usePlay()}
>
<i className="iconfont icon-bofang"></i>
<i className="iconfont icon-zanting hide"></i>
</div>
<div className="pv-time">
<span className="pv-currentTime">00:00:00</span>
<span>/</span>
<span className="pv-duration">00:00:00</span>
</div>
</div>
<div className="pc-con-r">
<div className="pv-listen ml">
<div className="pv-yl">
<p
className="pv-ol"
onMouseDown={(e) => this.vper.useListen(e)}
></p>
<p className="pv-bg"></p>
</div>
<div
className="pv-iconyl"
onClick={() => this.vper.useVolume()}
>
<i className="iconfont icon-yinliang"></i>
<i className="iconfont icon-jingyin hide"></i>
</div>
</div>
<div className="pv-speed ml">
<p
className="pv-spnum"
onMouseOver={(e) => this.vper.selectListShow(e)}
>
1x
</p>
<ul
className="selectList"
onClick={(e) => this.vper.useSpnum(e)}
>
<li>0.5x</li>
<li>1x</li>
<li>1.25x</li>
<li>1.5x</li>
<li>2x</li>
</ul>
</div>
<div
className="pv-screen ml"
onClick={() => this.vper.fullScreen()}
>
<i className="iconfont icon-quanping"></i>
<i className="iconfont icon-huanyuan hide"></i>
</div>
</div>
</div>
</div>
</div>
);
}
}
ReactDOM.render(<VamVideoPlayer />, document.getElementById("app"));
</script>
</body>
</html>
上面React版本可能有點老,但是邏輯不會變。大家可以使用最新版本或者腳手架來開發一個視訊播放器元件,這樣一切都是自己說了算。
結語
到這裡,我們使用五種方法來實踐一個自定義配置視訊播放器。夢想就這麼簡單地實現了!你可以檢視完整原始碼到我的github上,地址在這https://github.com/maomincoding/vamPlayer
。
專案中主要難點在於拖拽那塊,大家可以先自己嘗試著去理解,我將會在下一篇主要講述本專案所遇到的一些問題以及解決方法。歡迎及時關注我的動態哦~謝謝
歡迎關注我的公眾號前端歷劫之路
回覆關鍵詞電子書,即可獲取12本前端熱門電子書。
回覆關鍵詞紅寶書第4版,即可獲取最新《JavaScript高階程式設計》(第四版)電子書。
關注公眾號後,點選下方選單即可加我微信,我拉攏了很多IT大佬,建立了一個技術交流、文章分享群,期待你的加入。
作者:Vam的金豆之路
微信公眾號:前端歷劫之路
相關文章
- 自定義視訊播放器播放器
- Android進階:自定義視訊播放器開發(上)Android播放器
- Android進階:自定義視訊播放器開發(下)Android播放器
- 自定義視訊播放器與慢放滾輪播放器
- Android進階:十、自定義視訊播放器 1Android播放器
- 短視訊平臺開發,自定義一個彈窗樣式和內容
- android短視訊開發,自定義下拉選單Android
- 短視訊開發app,webservice自定義加入攔截器APPWeb
- 你有夢想嗎?華為雲學院助你實現夢想
- 短視訊APP開發帶飛你的創業夢APP創業
- CAD夢想畫圖如何自定義座標系統
- 如果你有夢想,就一定要捍衛它!
- Vue + WebRTC 實現音視訊直播(附自定義播放器樣式)VueWeb播放器
- 短視訊開發app,自定義帶進度條的視訊播放按鈕APP
- 從0到1搭建一款Vue可配置視訊播放器元件(Npm已釋出)Vue播放器元件NPM
- 10個有用的自定義鉤子vue.jsVue.js
- HarmonyOS NEXT應用開發—自定義檢視實現Tab效果
- “夢想江湖,從新出發”《新夢想世界》正式開啟
- ArtVideoPlayer:一個靈活的視訊播放器IDE播放器
- 使用VideoView做個實用的視訊播放器IDEView播放器
- 分享一個用 go 開發的一款跨雲 vpc 通訊專案Go
- 你的開發利器Spring自定義註解Spring
- rmvb用什麼視訊播放器win10_rmvb怎麼用視訊播放器開啟win10播放器Win10
- [譯] 使用自定義檔案模板加快你的應用開發速度
- 短視訊程式開發,簡易的自定義確認彈框AlertDialog
- 快速開發一個自定義 Spring Boot Starter,並使用它Spring Boot
- 分享一個功能很全的視訊播放器播放器
- AVFoundation | 封裝一個好用的視訊播放器封裝播放器
- flutter 用 CustomPaint 畫一個自定義的 CircleProgressBar (一)FlutterAI
- MediaCodec、OpenGL、OpenSL/AudioTrack 實現一款簡單的視訊播放器播放器
- [譯] 用 Flask 和 Vue.js 開發一個單頁面應用FlaskVue.js
- 自定義表單系統開源是否好用?
- 推薦一款管理系統專用低程式碼工具,一天開發一個系統不是夢!
- 使用flutter編寫一款視訊應用Flutter
- JavaScript自定義事件JavaScript事件
- 開發有新意的短視訊,你就是榮耀王者
- 一款開源桌面 YouTube 播放器播放器
- 一個強悍而優美的Android視訊播放器Android播放器