自定义播放器

211 阅读1分钟

效果图

image.png

你是不是也是觉得video 自带的样式不能满足你的需求 想要自己加自定义按钮呢

<!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" />
    <title>Document</title>
    <style>
      * {
        padding: 0;
        margin: 0;
        font-size: 12px;
      }
      .table-del-btn {
        color: red;
        cursor: pointer;
      }
      .table-sure-btn {
        color: #1297c4;
        cursor: pointer;
      }

      html {
        height: 100%;
        width: 100%;
      }

      body {
        height: 100%;
        width: 100%;
      }

      .video_player {
        background-color: rgba(0, 0, 0, 0.5);
        position: relative;
        width: 1000px;
        height: 500px;
        margin: 0 auto;
        overflow: hidden;
      }

      .video_player video {
        width: 100%;
        height: 100%;
      }

      .video_player .menu {
        position: absolute;
        width: 100%;
        height: 50px;
        bottom: 0;
        left: 0;
      }

      .video_player .menu .play {
        position: absolute;
        width: 50px;
        height: 30px;
        text-align: center;
        line-height: 30px;
        top: 50%;
        left: 30px;
        transform: translateY(-50%);
        background: url(./img/play.png) no-repeat;
        background-size: 16px 18px;
        background-position: center;
        cursor: pointer;
      }

      /* 截图 */
      .video_player .menu .cut {
        position: absolute;
        width: 55px;
        height: 20px;
        line-height: 20px;
        border: 1px solid white;
        /* border-radius: 10px; */
        color: white;
        text-align: center;
        top: 50%;
        right: 310px;
        transform: translateY(-50%);
        cursor: pointer;
      }

      .video_player .menu .cut img {
        width: 18px;
        height: 18px;
        vertical-align: bottom;
      }

      /* 下载窗口 */
      .video_player .menu .downBtn {
        position: absolute;

        line-height: 20px;
        width: 100px;
        height: 20px;
        border: 1px solid white;
        color: white;
        text-align: center;
        top: 50%;
        right: 200px;
        transform: translateY(-50%);
        cursor: pointer;
      }

      .downBtn img {
        width: 16px;
        vertical-align: sub;
      }

      .downBtn .downDialog {
        position: absolute;
        right: -190px;
        top: -330px;
        width: 380px;
        height: 300px;
        border-radius: 4px;
        /* background: rgba(255, 255, 255, 0.3);*/

        background: #fff;
        color: black;
        display: none;
        cursor: default;
      }

      .downDialog .down-title {
        height: 30px;
        line-height: 30px;
        border-bottom: 1px solid #ccc;
        display: flex;
        justify-content: space-between;
        font-weight: 500;
        font-size: 14px;
        text-align: left;
        color: #333;
      }
      .downDialog .down-title :first-child {
        padding-left: 20px;
      }
      .downDialog .down-title :last-child {
        cursor: pointer;
        padding-right: 5px;
      }
      .downDialog .dialog-main{
        padding: 0px 10px;
      }
      .downDialog .dialog-top {
        margin: 10px 0;
        line-height: 30px;
        display: flex;
        justify-content: space-between;
      }

      .downBtn .Controller div {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translateY(-50%) translateX(-50%);
        width: 5px;
        height: 100px;
        background-color: #ccc;
      }

      .time {
        position: absolute;
        width: 100px;
        height: 30px;
        color: white;
        text-align: center;
        line-height: 30px;
        top: 50%;
        left: 80px;
        transform: translateY(-50%);
      }

      /* 进度条 */
      .progress_bar {
        margin-left: 10px;
        cursor: pointer;
        position: absolute;
        top: -6px;
        left: 0;
        width: calc(100% - 20px);
        height: 6px;
        background-color: #ccc;
        transition: height 0.2s linear, top 0.2s linear;
        border-radius: 5px;
      }

      .progress_bar > div {
        width: 0px;
        height: 100%;
        /* background-color: rgb(250, 139, 12); */
        border-radius: 15px;
        background-color: white;
      }

      .progress_bar > i {
        position: absolute;
        top: -2px;
        left: 0px;
        transform: translateX(-50%);
        width: 10px;
        height: 10px;
        /* background-color: red; */
        background-color: white;
        border-radius: 20px;
        transition: height 0.2s linear, top 0.2s linear, width 0.2s linear;
      }

      /* 倍数 */
      li {
        list-style: none;
      }

      .speed {
        position: absolute;
        top: 50%;
        right: 140px;
        transform: translateY(-50%);
        color: white;
        text-align: center;
        line-height: 30px;
      }

      .speed div {
        width: 50px;
        height: 20px;
        line-height: 20px;
        border: 1px solid white;
        cursor: pointer;
      }

      .speed ul {
        position: absolute;
        top: -170px;
        left: -4px;
        padding-bottom: 25px;
        display: none;
      }

      .speed ul li {
        padding: 0 10px;
        background-color: rgba(255, 255, 255, 0.3);
      }

      .speed ul li:nth-of-type(1) {
        border-top-left-radius: 10px;
        border-top-right-radius: 10px;
      }

      .speed ul li:nth-last-of-type(1) {
        border-bottom-left-radius: 10px;
        border-bottom-right-radius: 10px;
      }

      .speed ul li:hover {
        background-color: #ccc;
      }

      .speed div:hover {
        background-color: #ccc;
      }

      /* 音量 */
      .volume {
        position: absolute;
        width: 55px;
        height: 20px;
        line-height: 20px;
        border: 1px solid white;
        color: white;
        text-align: center;
        top: 50%;
        right: 75px;
        transform: translateY(-50%);
        cursor: pointer;

        /* position: absolute;
        width: 50px;
        height: 30px;
        text-align: center;
        line-height: 30px;
        top: 50%;
        right: 50px;
        transform: translateY(-50%);
        background: url(./img/sound.png) no-repeat;
        background-size: 16px 18px;
        background-position: center;
        cursor: pointer; */
      }

      .volume  img {
        width: 16px;
        vertical-align: sub;
      }

      .volume > span {
        width: 50px;
        height: 30px;
        cursor: pointer;
      }

      .volume .Controller {
        position: absolute;
        top: -170px;
        width: 50px;
        height: 150px;
        border-radius: 10px;
        background-color: rgba(255, 255, 255, 0.3);
        display: none;
      }

      .volume .Controller div {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translateY(-50%) translateX(-50%);
        width: 5px;
        height: 100px;
        background-color: #ccc;
      }

      .volume .Controller div::before {
        position: absolute;
        content: '';
        bottom: 0;
        left: 50%;
        transform: translateX(-50%);
        width: 5px;
        height: 100px;
        background-color: white;
      }

      .volume .Controller div::after {
        position: absolute;
        content: '';
        bottom: 100px;
        left: 50%;
        transform: translateX(-50%) translateY(4px);
        width: 8px;
        height: 8px;
        background-color: white;
        border-radius: 10px;
      }

      /* 全屏 */
      .full {
        /* position: absolute;
        width: 50px;
        height: 30px;
        text-align: center;
        line-height: 30px;
        top: 50%;
        right: 10px;
        transform: translateY(-50%);
        background: url(./img/full.png) no-repeat;
        background-size: 16px 18px;
        background-position: center;
       */

        position: absolute;
        width: 55px;
        height: 20px;
        line-height: 20px;
        border: 1px solid white;
        color: white;
        text-align: center;
        top: 50%;
        right: 10px;
        transform: translateY(-50%);
        cursor: pointer;
      }

      .full > img {
        width: 16px;
        vertical-align: sub;
      }
    </style>
    <script src="./layui/layui.all.js"></script>
    <script src="./js/jquery-1.9.1.min.js"></script>
    <script src="./js/common.js"></script>
    <link rel="stylesheet" href="./layui/css/layui.css" />
    <link rel="stylesheet" href="./css/layui-reset.css" />
  </head>

  <body>
    <div class="video_player">
      <video src="./VID_20211111_103435.mp4"></video>
      <div class="menu">
        <div class="play"></div>
        <div class="cut">
          <img src="./img/cut.png" alt="" />
          截图
        </div>
        <div class="downBtn">
          <img src="./img/see.png" alt="" />
          <span>查看录像截图</span>
          <div class="downDialog">
            <div class="down-title">
              <div>查看录像截图</div>
              <div class="closeDown">
                <img src="./img/关闭.png" alt="" />
              </div>
            </div>
            <div class="dialog-main">
              <div class="dialog-top">
                截图数量:30张
                <button
                  type="button"
                  class="layui-btn-normal layui-btn layui-btn-sm"
                >
                  批量保存证据
                </button>
              </div>
              <div>
                <table class="layui-table" lay-skin="line">
                  <thead>
                    <tr>
                      <th width="50">序号</th>
                      <th width="120">播放时间</th>
                      <th width="120">截取状态</th>

                      <th width="90">操作</th>
                    </tr>
                  </thead>
                  <tbody>
                    <tr class="table_tr">
                      <th>1</th>
                      <th>00:15:12</th>
                      <th>等待截取</th>

                      <th>
                        <span class="table-sure-btn" onclick="preview(1)"
                          >预览</span
                        >
                        <span class="table-del-btn">删除</span>
                      </th>
                    </tr>
                    <tr class="table_tr">
                      <th>1</th>
                      <th>00:15:12</th>
                      <th>截取成功</th>

                      <th>
                        <span class="table-sure-btn" onclick="preview(2)"
                          >预览</span
                        >
                        <span class="table-del-btn">删除</span>
                      </th>
                    </tr>
                  </tbody>
                </table>
              </div>
            </div>
          </div>
        </div>
        <div class="time"></div>
        <div class="progress_bar">
          <div></div>
          <i></i>
        </div>
        <div class="speed">
          <div>倍数</div>
          <ul>
            <li>0.5x</li>
            <li>1.0x</li>
            <li>1.5x</li>
            <li>1.25x</li>
            <li>2.0x</li>
          </ul>
        </div>
        <div class="volume">
          
          <span><img src="./img/sound.png" alt="" />音量</span>
          <div class="Controller">
            <div></div>
            <i></i>
          </div>
        </div>
        <div class="full">
          <img src="./img/full.png" alt="" />
          <span id="fullText">全屏</span>
        </div>
      </div>
    </div>
    <script>
      function preview(params) {
        layer.open({
          type: 2,
          title: '预览',
          id: 'LAY_layuipro',
          area: ['500px', '500px'],
          content: './iframe.html' + '?data="1"',
        })
      }

      var video = document.getElementsByTagName('video')[0]
      var play = document.getElementsByClassName('play')[0]
      var cut = document.getElementsByClassName('cut')[0]
      var downBtn = document.getElementsByClassName('downBtn')[0]
      //隐藏截图
      // cut.style.display="none";

      var time = document.getElementsByClassName('time')[0]
      var bar = document.getElementsByClassName('progress_bar')[0]
      var Current = bar.getElementsByTagName('div')[0]
      var Dot = bar.getElementsByTagName('i')[0]
      var speed = document
        .getElementsByClassName('speed')[0]
        .getElementsByTagName('div')[0]
      var ul = document
        .getElementsByClassName('speed')[0]
        .getElementsByTagName('ul')[0]
      var Controller = document.getElementsByClassName('Controller')[0]
      var volume = document
        .getElementsByClassName('volume')[0]
        .getElementsByTagName('span')[0]
      var full = document.getElementsByClassName('full')[0]
      var video_player = document.getElementsByClassName('video_player')[0]
      var timer = null
      var lock = true
      play.onclick = function () {
        if (video.paused) {
          //判断是否已经播放了,如果还没播放,返回true
          video.play() //触发方法,播放视频
          play.style.backgroundImage = 'url(' + './img/pause.png' + ')'

          // play.innerHTML = '暂停' //修改 文字。
        } else {
          video.pause() //暂停播放。
          play.style.backgroundImage = 'url(' + './img/play.png' + ')'
          // play.innerHTML = '播放'
        }
      }
      //截图
      cut.onclick = function () {
        var currentTime = video.currentTime
        // alert(currentTime);
        console.log(currentTime)
      }
      downBtn.onclick = function () {
        var downDialog = document.getElementsByClassName('downDialog')[0]
        downDialog.style.display = 'block'
      }
      var closeDown = document.getElementsByClassName('closeDown')[0]
      closeDown.onclick = function () {
        console.log(222)

        var downDialog = document.getElementsByClassName('downDialog')[0]
        downDialog.style.display = 'none'
        event.stopPropagation()
      }

      function addZero(nub) {
        return nub > 9 ? nub : '0' + nub
      }

      video.onloadedmetadata = function () {
        // 视频加载完成触发,然后我们把时间添加到time标签上去。

        time.innerHTML =
          parseInt(video.currentTime / 60) +
          ':' +
          addZero(parseInt(video.currentTime % 60)) +
          'I' +
          parseInt(video.duration / 60) +
          ':' +
          addZero(parseInt(video.duration % 60))
      }

      setInterval(function () {
        //每隔 1秒,刷新一下时间。
        time.innerHTML =
          parseInt(video.currentTime / 60) +
          ':' +
          addZero(parseInt(video.currentTime % 60)) +
          'I' +
          parseInt(video.duration / 60) +
          ':' +
          addZero(parseInt(video.duration % 60))
        // Current.style.width =
        //   (video.currentTime / video.duration) *
        //     (parseInt(window.getComputedStyle(video, null).width)-10) +
        //   'px'
        // Dot.style.left =
        //   (video.currentTime / video.duration) *
        //   (parseInt(window.getComputedStyle(video, null).width)-10) +
        //   'px'
        Current.style.width =
          (video.currentTime / video.duration) * bar.offsetWidth + 'px'
        Dot.style.left =
          (video.currentTime / video.duration) * bar.offsetWidth + 'px'
      }, 100)

      bar.onmouseover = function () {
        //鼠标进入的时候,进度条变大
        this.style.top = '-10px'
        this.style.height = '10px'
        Dot.style.width = '18px'
        Dot.style.height = '18px'
        Dot.style.top = '-5px'
        this.style.cursor = 'pointer'
      }
      bar.onmouseout = function () {
        this.style.top = '-6px'
        this.style.height = '6px'
        Dot.style.width = '10px'
        Dot.style.height = '10px'
        Dot.style.top = '-2px'
      }

      bar.onmousedown = function (e) {
        // 鼠标点击的时候,跳转
        Current.style.width = e.layerX + 'px' //e.layerX 是点击的时候的位置。
        Dot.style.left = e.layerX + 'px'
        video.currentTime =
          (e.layerX / parseInt(window.getComputedStyle(video, null).width)) *
          video.duration //计算出点击的位置在总时间里面占多少。
        time.innerHTML =
          parseInt(video.currentTime / 60) +
          ':' +
          parseInt(video.currentTime % 60) +
          'I' +
          parseInt(video.duration / 60) +
          ':' +
          parseInt(video.duration % 60)
      }

      // 倍数
      speed.onclick = function () {
        ul.style.display = 'block'
        this.style.backgroundColor = '#ccc'
      }

      speed.onmouseout = function () {
        ul.style.display = 'none'
        this.style.backgroundColor = ''
      }

      ul.onmouseover = function () {
        ul.style.display = 'block'
        speed.style.backgroundColor = '#ccc'
      }
      ul.onmouseout = function () {
        ul.style.display = 'none'
        speed.style.backgroundColor = ''
      }

      var lis = ul.getElementsByTagName('li')
      for (var i = 0; i < lis.length; i++) {
        lis[i].onclick = function () {
          video.playbackRate = parseFloat(this.innerHTML) //调节倍数 0 到正无穷
          speed.innerHTML = this.innerHTML
        }
      }

      // 音量
      volume.onclick = function () {
        Controller.style.display = 'block'
      }

      Controller.getElementsByTagName('div')[0].onmousedown = function (e) {
        this.onmousemove = function (e) {
          if (100 - e.offsetY > 100) {
            // 这里为什么要减100 是因为,Y的顶点是0, 但是我们日常是用顶点是100,把数倒了而已。
            document.styleSheets[0].addRule(
              '.volume .Controller div::before',
              'height: 100px'
            ) // 修改伪元素。 因为我用的是伪元素做音量条
            document.styleSheets[0].addRule(
              '.volume .Controller div::after',
              'bottom: 100px'
            )
            video.volume = 1 // 修改音量。 0-1 之间, 1是默认音量
          } else if (100 - e.offsetY < 0) {
            document.styleSheets[0].addRule(
              '.volume .Controller div::before',
              'height: 0px'
            )
            document.styleSheets[0].addRule(
              '.volume .Controller div::after',
              'bottom: 0px'
            )
            video.volume = 0
          } else {
            document.styleSheets[0].addRule(
              '.volume .Controller div::before',
              'height: ' + (100 - e.offsetY) + 'px'
            )
            document.styleSheets[0].addRule(
              '.volume .Controller div::after',
              'bottom: ' + (100 - e.offsetY) + 'px'
            )
            video.volume = (100 - e.offsetY) * 0.01
          }
        }
        this.onmouseout = function () {
          Controller.onmousemove = function (e) {
            if (150 - e.offsetY - 25 > 100) {
              document.styleSheets[0].addRule(
                '.volume .Controller div::before',
                'height: 100px'
              )
              document.styleSheets[0].addRule(
                '.volume .Controller div::after',
                'bottom: 100px'
              )
              video.volume = 1
            } else if (150 - e.offsetY - 25 < 0) {
              document.styleSheets[0].addRule(
                '.volume .Controller div::before',
                'height: 0px'
              )
              document.styleSheets[0].addRule(
                '.volume .Controller div::after',
                'bottom: 0px'
              )
              video.volume = 0
            } else {
              document.styleSheets[0].addRule(
                '.volume .Controller div::before',
                'height: ' + (150 - e.offsetY - 25) + 'px'
              )
              document.styleSheets[0].addRule(
                '.volume .Controller div::after',
                'bottom: ' + (150 - e.offsetY - 25) + 'px'
              )
              video.volume = (150 - e.offsetY - 25) * 0.01
            }
            Controller.getElementsByTagName('div')[0].onmouseover =
              function () {
                Controller.onmousemove = false
                Controller.getElementsByTagName('div')[0].onmousemove = false
              }
          }
        }
        document.body.onmouseup = function () {
          Controller.onmousemove = false
          Controller.getElementsByTagName('div')[0].onmousemove = false
          Controller.getElementsByTagName('div')[0].onmouseout = false
          Controller.style.display = 'none'
          volume.style.backgroundColor = ''
        }
      }
      //监听结束
      video.addEventListener('ended', function () {
        // video.play()
        video.pause() //暂停播放。
        play.style.backgroundImage = 'url(' + './img/play.png' + ')'
        // play.innerHTML = '播放'
      })

      // 全屏
      full.onclick = function () {
        if (lock) {
          //声明一个变量来当状态。
          lock = false
          // video_player.style.height = document.body.offsetHeight + 143 + 'px' //获取屏幕的宽高
          // video_player.style.width = window.innerWidth + 'px'
          console.log(window)
          full.style.backgroundImage = 'url(' + './img/unfull.png' + ')'
          video_player.style.height = window.screen.height + 'px' //获取屏幕的宽高
          video_player.style.width = window.screen.width + 'px'
          document.documentElement.requestFullscreen() //全屏模式
        } else {
          lock = true
          video_player.style.height = 500 + 'px'
          video_player.style.width = 1000 + 'px'
          full.style.backgroundImage = 'url(' + './img/full.png' + ')'
          document.exitFullscreen() //退出全屏
        }
      }
    </script>
    <script>
      window.onresize = function () {
        if (!checkFull()) {
          video_player.style.height = 500 + 'px'
          video_player.style.width = 1000 + 'px'
        }
      }
      function checkFull() {
        var isFull =
          document.fullscreenElement ||
          document.mozFullScreenElement ||
          document.webkitFullscreenElement
        if (isFull === undefined) isFull = false
        return isFull
      }
    </script>
  </body>
</html>