HTML的vido原生js的使用

video标签自己自带的controls控件不能禁止下载

禁止下载:controlslist="nodownload" 但是这个只能在chrome58以上使用

所以只能手写控件

controller:
image

progress-bar:视频进度条总长度
image

progress-bar__current:当前视频进度条长度
image

先完成html部分

<div class="shadow hidden">  <!--  遮罩层-->
  <a class="close">x</a>  <!--关闭按钮,点击后视频和遮罩层一起关闭-->
  <div class="video-container"><!--放视频的容器-->
    <video src="" class="player" ></video> <!--video标签-->
    <div class="control-btn"><!--视频中间出现的大的播放/暂停控件,鼠标移入视频时出现,离开视频时消失-->
      <i class="iconfont v-bofang">&#xe608;</i>
    </div>
    <div class="controller"> <!--自己写的视频控件-->
      <div class="play-button"> <!--暂停播放按钮-->
        <i class="iconfont v-play">&#xe618;</i>
      </div>
      <div class="progress-box"><!--视频进度条父元素(拖拽进度条中用到)-->
        <div class="progress-box__shadow"> </div><!--视频进度条遮罩层(拖拽进度条中用到)-->
        <div class="progress-bar"> <!--视频进度条容器,也是视频进度条总长度-->
          <div class="progress-bar__current"></div><!--视频进度条的当前进度-->
          <div class="progress-bar__circle"></div><!--视频进度条上的小圆点-->
        </div>
      </div>
      <div class="duration"> <!--视频时长-->
        <div class="current-time">0:00</div>  <!--开始时间和当前播放时长-->
        /
        <div class="total-time"></div> <!--视频总时长,需要获取,用innerHTML写上去-->
      </div>
      <div class="sound"><!--视频音量-->
        <div class="sound-button">
          <i class="iconfont v-sound">&#xe662;</i><!--音量图标-->
        </div>  
        <div class="sound-box"><!--和视频一样的结构,音量进度条盒子-->
          <div class="sound-box__shadow"></div><!--音量进度条遮罩层-->
          <div class="sound-bar"> <!--音量进度条-->
            <div class="sound-bar__circle"></div> <!--当前音量进度条-->
            <div class="sound-bar__current"></div> <!--音量进度条小圆点-->
          </div>
        </div>
      </div>
      <div class="fullscreen"><!--全屏图标-->
        <i class="iconfont v-fullscreen">&#xe7a6;</i>
      </div>
    </div>
  </div>
</div>

js部分

①方法:接受一个url就可以播放视频

<script>
function play(url) {
     //找到视频
    const player =new VideoPlayer('.shadow .player');
    //找到遮罩层
    const shadow =document.querySelector('.shadow');
    //找到关闭按钮
    const close =document.querySelector('.shadow .close');    
    //找到视频的容器
    const videoContainer =document.querySelector('.shadow .video-container');
    //打开遮罩层
    shadow.classList.remove('hidden');
    //播放视频 ------ play方法在class对象里(后文会写到)
    player.play(url);
    //点击关闭按钮
    close.addEventListener('click',(e) => {
         //阻止a标签本来的事件
        e.stopPropagation();
        //关闭视频-----close方法在class对象里
        player.Close();
        //关闭遮罩层
        shadow.classList.add('hidden');
    });
    //点击遮罩层
    shadow.addEventListener('click',() => {
       //关闭视频
        player.Close();
        //关闭遮罩层
        shadow.classList.add('hidden');
    });
   //点击遮罩层的视频容器时,视频不能关闭
    videoContainer.addEventListener('click',(e) => {
       //阻止冒泡
        e.stopPropagation();
    });
}
</script>

②写视频播放控件的所有事件

用类对象写
类实际上是个特殊的函数,就像你能够定义的函数表达式和函数声明一样,类语法有两个组成
部分:类表达式和类声明。
定义一个类的一种方法是使用一个类声明。要声明一个类,你可以使用带有class关键字的类名
函数声明类声明之间的一个重要区别是函数声明会提升,类声明不会。你首先需要声明你的类,然后访问它,否则像下面的代码会抛出一个ReferenceError(引用错误)
类声明和类表达式的主体都执行在严格模式下。
constructor方法是一个特殊的方法,这种方法用于创建和初始化一个由class创建的对象。一个类只能拥有一个名为 “constructor”的特殊方法。如果类包含多个constructor的方法,则将抛出 一个SyntaxError
一个构造函数可以使用 super关键字来调用一个父类的构造函数。
static 关键字用来定义一个类的一个静态方法。调用静态方法不需要实例化该类,但不能通过一个类实例调用静态方法。静态方法通常用于为一个应用程序创建工具函数。
当一个对象调用静态或原型方法时,如果该对象没有“this”值
更多类相关知识在:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes

<script>
//图标对象(用unicode引用的方式使用图标)
const icons = {
  play: '&#xe619;',
  pause: '&#xe618;',
  fullscreen: '&#xe7a6;',
  sound: '&#xe662;',
  mute: '&#xe606;',
  bigPlay: '&#xe607;',
  bigPause: '&#xe608;',
};

class VideoPlayer {
  //初始化
  constructor(playerElement) {
    // 传进来的player
    this.$el = playerElement;
    //拖拽进度条时,初始化一个布尔值禁止鼠标移动元素
    this.moving = false;
    //video标签元素
    this.$audio = document.querySelector(playerElement);
    //video标签的父元素:视频容器
    this.$videoContainer = document.querySelector('.video-container');
    //视频自动播放
    this.$audio.autoplay = true;
    //视频自动循环
    this.$audio.loop = true;
    //初始化音量为0.5
    this.$audio.volume = 0.5;
    //控制条div class='controller'
    this.$controller = document.querySelector('.video-container .controller');
    //视频开关图标
    this.$playButton = this.$controller.querySelector('.play-button');
    //视频进度条
    this.$progress = this.$controller.querySelector('.progress-bar');
    //音量进度条
    this.$soundBar = this.$controller.querySelector('.sound-bar');
    //音量图标
    this.$soundButton = this.$controller.querySelector('.sound-button');
    //全屏图标
    this.$fullscreenButton = this.$controller.querySelector('.fullscreen');
    //视频进度条圆点
    this.$pin = this.$progress.querySelector('.progress-bar__circle');
    //音量进度条圆点
    this.$sound = this.$soundBar.querySelector('.sound-bar__circle');
    //视频进度条和遮罩层父元素:盒子
    this.$progressBox = this.$controller.querySelector('.progress-box .progress-box__shadow');
    //音量进度条和遮罩层父元素:盒子
    this.$soundBox = this.$controller.querySelector('.sound-box .sound-box__shadow');
    //视频中间的大图标
    this.$controlBtn = document.querySelector('.control-btn');
    //视频进度条
    this.videoBar = this.$progress.querySelector('.progress-bar__current');
    //声音进度条长度
    this.voiceBarWidth = parseFloat(window.getComputedStyle(this.$soundBar).width);
    //声音进度条
    this.Voicebar = this.$soundBar.querySelector('.sound-bar__current');
    //初始化进度条长度状态变量
    this.statusClock = "";
    //初始化预保存的音量状态变量
    this.previousVol = 0;
    //内部构造器调用完成视频各种功能的方法
    this.bindEvent();
  }

  //静态方法:计算视频时长
  static formatTime(time) {
    let min = Math.floor(time / 60);
    let sec = Math.floor(time % 60);
    sec = sec > 10 ? "" + sec : "0" + sec;
    return "0" + min + ":" + sec;
  }

  //方法:播放视频并更换图标
  playVideoAndChangeIcon(element, iconPause, iconPlay) {
    const icon = element.querySelector('.iconfont');
    //如果播放按钮上有play样式
    if (icon.classList.contains('play')) {
      //播放按钮变成停止按钮,播放视频
      icon.classList.remove('play');
      icon.innerHTML = iconPause;
      this.$audio.play();
    } else {
      //否则按钮变成播放按钮,停止播放视频
      icon.classList.add('play');
      icon.innerHTML = iconPlay;
      this.$audio.pause();
    }
  }

  //方法:声音和视频的mousedown事件
  myDown(elem) {
    //可以移动元素
    this.moving = true;
    //打开遮罩层
    elem.style.display = 'block';
  }

  //方法:声音和视频的mouseup事件
  myUp(elem) {
    //禁止移动元素
    this.moving = false;
   //关闭遮罩层
    elem.style.display = 'none';
  }

  //方法:播放视频-----外部调用的方法
  play(url) {
    //因为关闭视频的时候$audio被定义为null,所以播放时要重新定义$audio
    this.$audio = document.querySelector(this.$el);
    this.$audio.src = url;
  }

  //方法:关闭视频-----外部调用的方法
  Close() {
    this.$audio.pause();
    //关闭视频的同时清除更新定时器
    clearInterval(this.statusClock);
  }

  //方法:结束播放-----this.bindEvent调用的方法
  pause() {
    this.$audio.pause();
  }

  //视频状态的更新----this.bindEvent调用的方法
  updateStatus() {
    //current-time上写视频播放的当前时间
    this.$controller.querySelector(".current-time").innerHTML =VideoPlayer.formatTime(this.$audio.currentTime);
    //进度条长度
    let percent = this.$audio.currentTime / this.$audio.duration;
    this.$controller.querySelector(".progress-bar__current").style.width = percent * 100 + '%';
    this.$controller.querySelector(".progress-bar__circle").style.left = percent * 100 + '%';
  }
  //内部构造器调用的完成视频各种功能的方法
  bindEvent() {
    const _this = this;
    //禁止右键功能
    this.$audio.addEventListener("contextmenu", (e) => {
      e.preventDefault();
    });
    //点击播放按钮播放视频
    this.$playButton.addEventListener('click', () => {
      this.playVideoAndChangeIcon(this.$playButton, icons.pause, icons.play);
    });
    //点击音量按钮,静音
    this.$soundButton.addEventListener('click', () => {
      const icon = this.$soundButton.querySelector('.iconfont');
      //如果此时的icon为音量按钮
      if (icon.classList.contains('voice')) {
        icon.classList.remove('voice');
        //换图标
        icon.innerHTML = icons.sound;
        //恢复当前视频的音量为之前保存的静音前的音量状态
        this.$audio.volume = this.previousVol;
        //回复变量previousVol为初始状态
        this.previousVol = 0;
        //进度条长度
        //如果音量为0
        if(this.$audio.volume === 0){
          //进度条的长度
          this.$sound.style.left = 3 + 'px';
          this.Voicebar.style.width = 3 + 'px';
        }else {//否则的长度
          this.$sound.style.left = parseFloat(window.getComputedStyle(this.$soundBar).width) * this.$audio.volume + 'px';
          this.Voicebar.style.width = parseFloat(window.getComputedStyle(this.$soundBar).width) * this.$audio.volume + 'px';
        }
      } else {//否则
        //icon为静音按钮
        icon.classList.add('voice');
        icon.innerHTML = icons.mute;
        //保存当前音量状态
        this.previousVol = this.$audio.volume;
        //静音
        this.$audio.volume = 0;
        //进度条长度:因为小圆点也有宽度,所以要计算进去,我设置的小圆点的宽为10px
        this.$sound.style.left = 3 + 'px';
        this.Voicebar.style.width = 3 + 'px';
      }
    });
    //点击进度条移动视频进度条和圆点
    this.$progress.addEventListener('click', event => {
      const barVideoWidth = parseFloat(window.getComputedStyle(this.$progress).width);
      let percent = event.offsetX / barVideoWidth;
      this.$audio.currentTime = this.$audio.duration * percent;
      this.$pin.style.left = event.offsetX + 'px';
      this.videoBar.style.width = event.offsetX + 'px';
      this.auto = true;
    });
    //拖拽圆点移动视频进度条和圆点
    this.$pin.addEventListener('mousedown', () => {
      //允许鼠标移动圆点并打开遮罩层
      this.myDown(this.$progressBox);
    });
    //注意:为了避免点击到进度条,所以鼠标移动事件绑定到遮罩层上,圆点在遮罩层上移动
    //这样滑动圆点的时候就不会出现由于点到进度条而移动失败
    this.$progressBox.addEventListener('mousemove', event => {
      //阻止冒泡
      event.stopPropagation();
      if (this.moving) {
        const barVideoWidth = parseFloat(window.getComputedStyle(this.$progress).width);
        let percent = event.offsetX / barVideoWidth;
        this.$audio.currentTime = this.$audio.duration * percent;
        this.$pin.style.left = event.offsetX + 'px';
        this.videoBar.style.width = event.offsetX + 'px';
      }
    });
    document.addEventListener('mouseup', () => {
       //不允许鼠标移动圆点并关闭遮罩层
      this.myUp(this.$progressBox);
    });
    //点击移动音量进度条和圆点
    this.$soundBar.addEventListener('click', event => {
      //音量要大于0,不加这个出现过音量小于0的bug
      let x = Math.max(0, event.offsetX);
      this.$audio.volume = x / this.voiceBarWidth;
      this.$sound.style.left = event.offsetX + 'px';
      this.Voicebar.style.width = event.offsetX + 'px';
      const icon = this.$soundButton.querySelector('.iconfont');
      if (event.offsetX <= 3) {
        this.$audio.volume = 0;
        icon.innerHTML = icons.mute;
        this.$sound.style.left = 3 + 'px';
        this.Voicebar.style.width = 3 + 'px';
      } else {
        icon.innerHTML = icons.sound;
      }
    });
    //拖拽移动音量进度条和圆点
    this.$sound.addEventListener('mousedown', () => {
      this.myDown(this.$soundBox);
    });
    this.$soundBox.addEventListener('mousemove', event => {
      event.stopPropagation();
      if (this.moving) {
        let x = Math.max(0, event.offsetX);
        this.$audio.volume = x / this.voiceBarWidth;
        this.$sound.style.left = event.offsetX + 'px';
        this.Voicebar.style.width = event.offsetX + 'px';
        const icon = this.$soundButton.querySelector('.iconfont');
        if (event.offsetX <= 4) {
          this.$audio.volume = 0;
          icon.innerHTML = icons.mute;
          this.$sound.style.left = 4 + 'px';
          this.Voicebar.style.width = 4 + 'px';
        } else {
          icon.innerHTML = icons.sound;
        }
      }
    });
    document.addEventListener('mouseup', () => {
      this.myUp(this.$soundBox);
    });
    //播放时
    this.$audio.addEventListener('play', () => {
      //先清除一次计时器
      clearInterval(this.statusClock);
      //0.5秒更新一次进度条长度
      this.statusClock = setInterval(function () {
        _this.updateStatus();
      }, 500);
      //视频总共有多长的时间
      this.$controller.querySelector(".total-time").innerHTML = VideoPlayer.formatTime(this.$audio.duration);
    });
    //暂停时清除计时器
    this.$audio.addEventListener("pause", function () {
      clearInterval(this.statusClock);
    });
    //全屏和取消全屏
    //只能网页全屏不能电脑屏幕全屏,因为电脑屏幕全屏后不知为何视频无法点击全屏
    this.$fullscreenButton.addEventListener('click', () => {
      if (!this.$videoContainer.classList.contains("open")) {
        this.$videoContainer.classList.add('open');
      } else {
        this.$videoContainer.classList.remove("open");
      }
    });
    //大图标控制播放和关闭
    //大图标的出现和消失
    this.$videoContainer.addEventListener('click', () => {
      //点击屏幕,播放图标出现并视频暂停
      this.playVideoAndChangeIcon(this.$controlBtn, icons.bigPause, icons.bigPlay);
      this.$controlBtn.style.display = 'block';
    });
    //点到控制条时
    this.$controller.addEventListener('click',(e) => {
      //阻止冒泡
      e.stopPropagation();
    });
    //鼠标移入视频屏幕
    this.$videoContainer.addEventListener('mouseenter',()=>{
      //如果视频处于暂停状态
      if(this.$audio.paused){
        //播放图标出现
        this.$controlBtn.style.display = 'block';
      }
    });
    //鼠标移出屏幕
    this.$videoContainer.addEventListener('mouseleave', () => {
      //播放图标消失
      this.$controlBtn.style.display = 'none';
    });
  }
}
</script>

最后是css样式:

/*引入并使用图标前记得去网站下载图标代码,保存在自己项目中*/
@font-face {
  font-family: 'iconfont';  /* project id 1324873 */
  src: url('//at.alicdn.com/t/font_1324873_mett0wusfe.eot');
  src: url('//at.alicdn.com/t/font_1324873_mett0wusfe.eot?#iefix') format('embedded-opentype'),
  url('//at.alicdn.com/t/font_1324873_mett0wusfe.woff2') format('woff2'),
  url('//at.alicdn.com/t/font_1324873_mett0wusfe.woff') format('woff'),
  url('//at.alicdn.com/t/font_1324873_mett0wusfe.ttf') format('truetype'),
  url('//at.alicdn.com/t/font_1324873_mett0wusfe.svg#') format('svg');
}
.iconfont{
  font-family:"iconfont" !important;
  font-size:16px;font-style:normal;
  -webkit-font-smoothing: antialiased;
  -webkit-text-stroke-width: 0.2px;
  -moz-osx-font-smoothing: grayscale;
  cursor: pointer;
}
* {
  box-sizing: border-box;
}
.iconfont {
  color: white;
}
@keyframes show {
  from {
    bottom: -30px;
  }
  to {
    bottom: 0;
  }
}
.shadow {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  background: rgba(0, 0, 0, .6);
}

.shadow.hidden {
  display: none;
}

.shadow .close{
  display:block;
  width: 32px; height:32px;
  border-radius:50%;
  position:absolute;
  right:20px; top:20px;
  text-align:center;
  line-height: 26px;
  font-size: 24px;
  color:#aaaaaa;
  text-decoration: none;
  box-shadow:0 0 7px 1px #aaaaaa;
  opacity: 0.5;
  transition:all .5s linear;
  cursor: pointer;
}
.shadow .close:hover{
  box-shadow:0 0 7px 1px #cccccc;
  background: #222222;
  opacity: 1;
}
.shadow .video-container {
  width: 900px;
  height: 506px;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  overflow: hidden;
  background: black;
}
.shadow .video-container.open {
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0;
  bottom: 0;
  right: 0;
  top: 0;
  overflow: hidden;
  transform: none;
}

.shadow .video-container .player {
  width: 100%;
  height: 100%;
}

.shadow .video-container .controller {
  display: none;
  position: absolute;
  bottom: 0;
  height: 40px;
  width: 100%;
  background-image: linear-gradient(to bottom,rgba(0, 0, 0, .1), rgba(0, 0, 0, 1));
  z-index:217483647;
}
.shadow .video-container:hover .controller {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 18px;
  animation: show 1s;
}
.video-container .play-button {
  padding: 1px;
  width: 30px;
}
.controller .progress-bar {
  position: relative;
  width: 100%;
  height: 4px;
  border-radius: 8px;
  background: rgba(0, 0, 0, .8);
  cursor: pointer;
}
.controller .progress-box,.controller .sound-box{
  position: relative;
  width: 80%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.controller .progress-box .progress-box__shadow,.controller .sound-box .sound-box__shadow{
  display: none;
  position: absolute;
  content: "";
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  background: transparent;
  cursor: pointer;
  user-select: none;
  z-index: 10;
}
.controller .progress-bar .progress-bar__circle {
  position: absolute;
  top: -5px;
  left: 50%;
  transform: translate(-50%, 0);
  height: 14px;
  width: 14px;
  border-radius: 50%;
  background: #cccccc;
}
.controller .progress-bar .progress-bar__current {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 50%;
  border-radius: 8px;
  background: #c0c0c0;
  z-index:1;
}
.controller .duration {
  display: flex;
  justify-content: space-around;
  align-items: center;
  width: 80px;
  margin: 0 10px;
  font-size: 14px;
  color: white;
}
.controller .sound {
  width: 100px;
  height:100%;
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0 10px;
}
.controller .sound .sound-button {
  width: 20px;
  margin: 0 10px;
}
.controller .sound .sound-bar {
  position: relative;
  width: 80px;
  height: 4px;
  border-radius: 8px;
  background: rgba(0, 0, 0, .8);
  cursor: pointer;
 }
.controller .sound .sound-bar__circle {
  position: absolute;
  top: -3px;
  left: 50%;
  transform: translate(-50%, 0);
  height: 10px;
  width: 10px;
  border-radius: 50%;
  background: #cccccc;
}
.controller .sound .sound-bar__current {
  position: absolute;
  top: 0;
  bottom: -1px;
  left: 0;
  width: 50%;
  border-radius: 8px;
  background: #c0c0c0;
}
.fullscreen{
  margin-left: 14px;
}
.control-btn{
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
  display: none;
  opacity: 0.6;
}
.control-btn:hover{
  opacity: 1;
}
.control-btn .v-bofang{
  font-size:78px;
  text-align: center;
  color:#ffffff;
}
.control-btn .v-bofang:hover{
  font-size:78px;
  text-align: center;
}

video::-webkit-media-controls{
  display:none !important;
}

我的github示例:[demo](https://evaspec.github.io/video/index.html](https://evaspec.github.io/video/index.html)

我的完整代码:video-demo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容