你是否有一个梦想?用JavaScript开发一款自定义配置视频播放器

Jacquelyn38
• 阅读 1547

前言

沉寂了一周了,打算把这几天的结果呈现给大家。这几天抽空就一直在搞一个自定义视频播放器,为什么会有如此想法?是因为之前看一些学习视频网站时,看到它们做的视频播放器非常Nice!于是,就打算抽空开发一款属于自己的视频播放器。话不多说,一起来实战吧!

项目展示

你是否有一个梦想?用JavaScript开发一款自定义配置视频播放器

(这只是一张图片哦~)

这张图就是我们的成品,还等什么?赶紧来实战吧!

实战

我会把完整源码放在github上,欢迎来star,地址在文末。

首先,我们会使用最原生的JavaScript来实现,老大哥肯定要打头阵啊!

一、JavaScript

  1. iconfont.css:阿里字体图标文件,你可以在上面找到很多漂亮的图标。

  2. index.css:项目样式文件。

  3. 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类

  1. 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;  
  };  
}  
``

这样不仅可以自定义配置一个视频播放器,逻辑文件中的每一个方法函数还非常的简单明了,可以说是达到我们要求的目的了。但是我们可以更简洁。

三、模板字符串

  1. 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" 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>  
`;  
``

我们再进一步,使用Vue.js、React.js分别实现一波。

四、Vue.js

  1. 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

  1. react.development.js - React 的核心库。

  2. react-dom.development - 提供与 DOM 相关的功能。

  3. 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大佬,创建了一个技术交流、文章分享群,期待你的加入。你是否有一个梦想?用JavaScript开发一款自定义配置视频播放器

- END -

你是否有一个梦想?用JavaScript开发一款自定义配置视频播放器

本文转转自微信公众号前端历劫之路原创https://mp.weixin.qq.com/s/cPPy-tT3N4BNotNxbHLv4A,如有侵权,请联系删除。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Jacquelyn38 Jacquelyn38
3年前
从0到1搭建一款Vue可配置视频播放器组件(Npm已发布)
前言话不多说,这篇文章主要讲述如何从0到1搭建一款适用于Vue.js的自定义配置视频播放器。我们平时在PC端网站上观看视频时,会看到有很多丰富样式的视频播放器,而我们自己写的video标签样式却是那么丑。其实像那些网站都是基于原生video标签进行开发的,只不过还得适当加工一下,才会有我们所看到的漂亮的视频播放器。开发在具体开发之前,我们需要明确我们需要做什
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
35岁是技术人的天花板吗?
35岁是技术人的天花板吗?我非常不认同“35岁现象”,人类没有那么脆弱,人类的智力不会说是35岁之后就停止发展,更不是说35岁之后就没有机会了。马云35岁还在教书,任正非35岁还在工厂上班。为什么技术人员到35岁就应该退役了呢?所以35岁根本就不是一个问题,我今年已经37岁了,我发现我才刚刚找到自己的节奏,刚刚上路。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这