封装一个视频组件(可模拟画中画效果)

简介: 封装一个视频组件(可模拟画中画效果)

前言:


我是用的原生js写的这个功能,因此这个组件在vue、react、jquery等框架中均可使用,例如,我就是用在基于nuxt.js框架+typescript项目中的,用来做点击某按钮,弹出视频,模拟画中画效果。

1.效果:


1.在页面中可以随意拖拽

2.可以用鼠标动态控制大小,且宽高是按比例放大或缩小

3.点击右上角可以关闭视频

4.点击按钮打开时,自动播放

5.全凭遮罩效果及控制视频弹出位置

ps:处理bug完毕,关闭时声音关不掉。

2.效果图:


image.png

3.代码实现


封装组件名为 video.vue

建议:封装为组件后,可以通过vuex传值来控制视频的打开和关闭。

强烈警告:用v-if而不要使用v-show控制此组件的显示隐藏!!!

【如果用v-if不能拖动或者放大缩小,可以用v-show,然后可以设置一个控制音量的小图标,点击的时候让muted为false,高级浏览器默认自动播放时不能有声音,可以通过muted控制】

<template>
  <div>
    <div id="div2" ref="div2" v-show="open">
      <div style="width: 100%; height: 100%; overflow: hidden">
        <div id="close" @click="close">x</div>
        <h2 id="h2"></h2>
        <video id="sonVideo" preload="auto" width="100%" height="100%" autoplay  :muted="shengyin">
          <source
            src="写你的视频地址,我的就不贴了,可以随意找个视频的地址 "
          />
        </video>
        <div id="right"></div>
        <div id="div1"></div>
        <div id="bottom"></div>
        <div id="left"></div>
      </div>
    </div>
    <!-- <div id="zhezhao"></div>  遮罩功能可以用 -->
  </div>
</template>
<script>
export default {
  data () {
    return {
      open: false,
      shengyin:false //声音控制
    }
  },
  methods: {
    close () {
      this.open = false
    }
  },
  mounted () {
    // window.onload=function(){
    this.$nextTick(() => {
      // window.onload=function(){
      var oDiv = document.getElementById("div1")
      var oDiv2 = document.getElementById("div2")
      var zhezhao = document.getElementById("zhezhao")
      var h2 = document.getElementById("h2")
      var right = document.getElementById("right")
      var bottom = document.getElementById("bottom")
      var sClose = document.getElementById("close")
      var sonVideo = document.getElementById("sonVideo")
      var mouseStart = {}
      var divStart = {}
      var rightStart = {}
      var bottomStart = {}
      if(right){
        //右边鼠标按下
      right.onmousedown = function (ev) {
        var oEvent = ev || event //e.XX
        mouseStart.x = oEvent.clientX //鼠标的x坐标--起始位置
        mouseStart.y = oEvent.clientY  //鼠标的y坐标
        rightStart.x = right.offsetLeft //元素(div)到浏览器边框的距离
        if (right.setCapture)
        //多用于容器对象,效果是对指定的对象设置鼠标捕获。
        // 所谓鼠标捕获,是指对鼠标事件( ondblclick, onmouseout)进行捕捉,
        // 使在容器内的子对象的鼠标事件均由容器对象触发,因此,只能在容器对象的鼠标事件函数中进行处理。
        // 当参数为true时,对鼠标进行捕捉,相反,不捕捉。
        // 与这个函数对应,releaseCapture方法释放鼠标捕获,并触发onlosecapture事件。
        {
          right.onmousemove = doDrag1 //鼠标移动时,拖拽
          right.onmouseup = stopDrag1 //鼠标抬起时,停止拖拽
          right.setCapture()
        }
        else {
          document.addEventListener("mousemove", doDrag1, true)
          document.addEventListener("mouseup", stopDrag1, true)
        }
      }
      }
      function doDrag1 (ev) {
        // clientX、clientY
        //点击位置距离当前body可视区域的x,y坐标
        var oEvent = ev || event
        var l = oEvent.clientX - mouseStart.x + rightStart.x
        var w = l + oDiv.offsetWidth
        if (w < oDiv.offsetWidth) {
          w = oDiv.offsetWidth
        }
        else if (w > document.documentElement.clientWidth - oDiv2.offsetLeft) {
          w = document.documentElement.clientWidth - oDiv2.offsetLeft - 2
        }
        oDiv2.style.width = w + "px"
        oDiv2.style.height = w * 0.56 + "px"
      };
      function stopDrag1 () {
        if (right.releaseCapture) {
          right.onmousemove = null
          right.onmouseup = null
          right.releaseCapture()
        }
        else {
          document.removeEventListener("mousemove", doDrag1, true)
          document.removeEventListener("mouseup", stopDrag1, true)
        }
      };
      if(bottom){
        //底部边框按下
      bottom.onmousedown = function (ev) {
        var oEvent = ev || event
        mouseStart.x = oEvent.clientX
        mouseStart.y = oEvent.clientY
        bottomStart.y = bottom.offsetTop
        if (bottom.setCapture) {
          bottom.onmousemove = doDrag2
          bottom.onmouseup = stopDrag2
          bottom.setCapture()
        }
        else {
          document.addEventListener("mousemove", doDrag2, true)
          document.addEventListener("mouseup", stopDrag2, true)
        }
      }
      }
      function doDrag2 (ev) {
        var oEvent = ev || event
        var t = oEvent.clientY - mouseStart.y + bottomStart.y
        var h = t + oDiv.offsetHeight
        if (h < oDiv.offsetHeight) {
          h = oDiv.offsetHeight
        }
        else if (h > document.documentElement.clientHeight - oDiv2.offsetTop) {
          h = document.documentElement.clientHeight - oDiv2.offsetTop - 2
        }
        oDiv2.style.height = h + "px"
        oDiv2.style.width = h * 1.56 + "px"
      };
      function stopDrag2 () {
        if (bottom.releaseCapture) {
          bottom.onmousemove = null
          bottom.onmouseup = null
          bottom.releaseCapture()
        }
        else {
          document.removeEventListener("mousemove", doDrag2, true)
          document.removeEventListener("mouseup", stopDrag2, true)
        }
      };
      if(oDiv){
             //大盒子按下
      oDiv.onmousedown = function (ev) {
        var oEvent = ev || event
        mouseStart.x = oEvent.clientX
        mouseStart.y = oEvent.clientY
        divStart.x = oDiv.offsetLeft
        divStart.y = oDiv.offsetTop
        if (oDiv.setCapture) {
          oDiv.onmousemove = doDrag
          oDiv.onmouseup = stopDrag
          oDiv.setCapture()
        }
        else {
          document.addEventListener("mousemove", doDrag, true)
          document.addEventListener("mouseup", stopDrag, true)
        }
        zhezhao.style.display = "block"
      }
      }
      function doDrag (ev) {
        var oEvent = ev || event
        var l = oEvent.clientX - mouseStart.x + divStart.x
        var t = oEvent.clientY - mouseStart.y + divStart.y
        var w = l + oDiv.offsetWidth
        var h = t + oDiv.offsetHeight
        if (w < oDiv.offsetWidth) {
          w = oDiv.offsetWidth
        }
        else if (w > document.documentElement.clientWidth - oDiv2.offsetLeft) {
          w = document.documentElement.clientWidth - oDiv2.offsetLeft - 2
        }
        if (h < oDiv.offsetHeight) {
          h = oDiv.offsetHeight
        }
        else if (h > document.documentElement.clientHeight - oDiv2.offsetTop) {
          h = document.documentElement.clientHeight - oDiv2.offsetTop - 2
        }
        oDiv2.style.width = w + "px"
        oDiv2.style.height = h + "px"
      };
      function stopDrag () {
        if (oDiv.releaseCapture) {
          oDiv.onmousemove = null
          oDiv.onmouseup = null
          oDiv.releaseCapture()
        }
        else {
          document.removeEventListener("mousemove", doDrag, true)
          document.removeEventListener("mouseup", stopDrag, true)
        }
        zhezhao.style.display = "none"
      };
      if(h2){
           //h2上边按下
      h2.onmousedown = function (ev) {
        var oEvent = ev || event
        mouseStart.x = oEvent.clientX
        mouseStart.y = oEvent.clientY
        divStart.x = oDiv2.offsetLeft
        divStart.y = oDiv2.offsetTop
        if (h2.setCapture) {
          h2.onmousemove = doDrag3
          h2.onmouseup = stopDrag3
          h2.setCapture()
        }
        else {
          document.addEventListener("mousemove", doDrag3, true)
          document.addEventListener("mouseup", stopDrag3, true)
        }
        // zhezhao.style.display = "block"
      }
      }
      function doDrag3 (ev) {
        var oEvent = ev || event
        var l = oEvent.clientX - mouseStart.x + divStart.x
        var t = oEvent.clientY - mouseStart.y + divStart.y
        if (l < 0) {
          l = 0
        }
        else if (l > document.documentElement.clientWidth - oDiv2.offsetWidth) {
          l = document.documentElement.clientWidth - oDiv2.offsetWidth
        }
        if (t < 0) {
          t = 0
        }
        else if (t > document.documentElement.clientHeight - oDiv2.offsetHeight) {
          t = document.documentElement.clientHeight - oDiv2.offsetHeight
        }
        oDiv2.style.left = l + "px"
        oDiv2.style.top = t + "px"
      };
      function stopDrag3 () {
        if (h2.releaseCapture) {
          h2.onmousemove = null
          h2.onmouseup = null
          h2.releaseCapture()
        }
        else {
          document.removeEventListener("mousemove", doDrag3, true)
          document.removeEventListener("mouseup", stopDrag3, true)
        }
        // zhezhao.style.display = "none"
      }
      //关闭窗口
      if(sClose){
        sClose.onmousedown = function (ev) { (ev || event).cancelBubble = true }
        sClose.onclick = function () {
        // console.log(window.$nuxt);
        // oDiv2.style.display="none";
        console.log(sonVideo.muted,'sonVideo.mounted');
        sonVideo.muted = true
        // };
        // }
      }
      }
    })
  },
}
</script>
<style scoped>
* {
  margin: 0;
  padding: 0;
}
/* #zhezhao{
    width:100%;
    height:100%;
    background:#f00;
    filter:alpha(opacity:0);
    opacity:0;
    z-index:9999;
    position:absolute;
    top:0;
    left:0;
    display:none;
    } */
#div2 {
  width: 762px;
  min-width: 500px;
  min-height: 280px;
  height: 429px;
  display: block;
  overflow: hidden;
  position: fixed;
  top: 30%; /* 控制视频出现的位置 */
  left: 30%;
  background: #eeeeee;
  z-index: 999999;
  padding: 0 15px 20px;
  /* border:20px solid #f00; */
}
#div1 {
  width: 15px;
  height: 15px;
  background: rgba(rgb(240, 234, 234), alpha);
  position: absolute;
  right: 0px;
  bottom: 0px;
  cursor: nw-resize;
  overflow: hidden;
  font-size: 12px;
  text-align: center;
  line-height: 15px;
  color: #ffffff;
  float: right;
  z-index: 3;
}
#right {
  /*右边的可以拖动的框  */
  width: 15px;
  height: 100%;
  background: #ffffff;
  float: right;
  position: absolute;
  right: 0;
  top: 0;
  cursor: e-resize;
  overflow: hidden;
  /* filter: alpha(opacity: 0); */
  opacity: 1;
  z-index: 1;
}
#left {
  /*左边的可以拖动的框  */
  width: 15px;
  height: 100%;
  background: #ffffff;
  float: left;
  position: absolute;
  left: 0;
  top: 0;
  cursor: e-resize;
  overflow: hidden;
  /* filter: alpha(opacity: 0); */
  opacity: 1;
  z-index: 1;
}
/* 最底下的绿色的 */
#bottom {
  width: 100%;
  height: 15px;
  background: #ffffff;
  position: absolute;
  left: 0;
  bottom: 0;
  cursor: n-resize;
  overflow: hidden;
  /* filter: alpha(opacity: 0); */
  opacity: 1;
  z-index: 1;
}
#div2 p {
  padding: 10px;
  line-height: 24px;
  font-size: 13px;
  text-indent: 24px;
  color: #996600;
}
#div2 h2 {
  width: 100%;
  height: 25px;
  line-height: 25px;
  font-size: 14px;
  background: #fff;
  color: #ffffff;
  text-indent: 15px;
  cursor: move;
  overflow: hidden;
  position: relative;
  z-index: 9999;
}
#close {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 999999;
  line-height: 25px;
  font-weight: normal;  
  cursor: pointer;
  display: block;
  background-color:red ;
  text-align: center;
  width:30px;
  height: 25px;
  color: #fff;
}
</style>
相关文章
|
5月前
|
编解码 API 开发工具
Android平台轻量级RTSP服务模块二次封装版调用说明
本文介绍了Android平台上轻量级RTSP服务模块的二次封装实践,旨在简化开发流程,让开发者能更专注于业务逻辑。通过`LibPublisherWrapper`类提供的API,可在应用中轻松初始化RTSP服务、配置视频参数(如分辨率、编码类型)、启动与停止RTSP服务及流发布,并获取RTSP会话数量。此外,还展示了如何处理音频和视频数据的采集与推送。最后,文章提供了从启动服务到销毁资源的完整示例,帮助开发者快速集成实时流媒体功能。
|
6月前
|
JavaScript
vue + element UI【实战】音乐播放器/语音条(内含音频的加载、控制,事件监听,信息获取,手机网页阴影的去除等技巧)
vue + element UI【实战】音乐播放器/语音条(内含音频的加载、控制,事件监听,信息获取,手机网页阴影的去除等技巧)
136 1
|
小程序 开发者
wepy框架-触摸内容滑动组件使用步骤
wepy框架-触摸内容滑动组件使用步骤
52 0
|
小程序 JavaScript 前端开发
小程序封装加载动画
在小程序的开发中,页面的加载过程可能会因为网络状况的不好或数据量的过大而显得非常缓慢,这时候加上一个加载动画就能有效的缓解用户的等待焦虑感。而对于应用的多个页面来说,使用全局加载动画可以提高用户体验,让应用显得更加美观和专业。本篇技术分享博客将为大家介绍在小程序中封装全局加载动画的具体实现步骤,帮助您提高小程序的用户体验。通过上述步骤,我们就完成了小程序中封装全局加载动画的具体实现方法。在实际开发中,我们可以根据实际需求对组件样式和方法进行调整和修改,以满足不同的开发需求。
282 0
|
Java Maven Android开发
Android组件化开发(六)-- 短视频播放组件封装
前面几篇文章我们封装了几个组件化功能组件: 包括:`网络请求组件`,`图片加载请求组件`,`应用保活组件`,`音乐播放组件封装`。 > 每个组件都可以直接拿到自己项目中使用,当然还需根据自己项目要求进行优化。
|
iOS开发
iOS开发 - 滑动控制屏幕亮度和系统音量(附加AVAudioPlayer基本用法和Masonry简单使用)
iOS开发 - 滑动控制屏幕亮度和系统音量(附加AVAudioPlayer基本用法和Masonry简单使用)
245 0
iOS开发 - 滑动控制屏幕亮度和系统音量(附加AVAudioPlayer基本用法和Masonry简单使用)
|
缓存
封装一下图片下载功能
封装一下图片下载功能
112 0
封装一下图片下载功能
|
开发工具 C++
C++音乐播放按钮的封装过程详解
1、准备工作:音乐、开发工具VS stdio及图形库工具 2、设计思路:先加载音乐,再通过点击不同的按钮执行不同的操作(播放音乐,暂停音乐、继续播放、结束播放) 绘制按钮我们通过一个按钮button类来操作,这样数据会存在一些必要的访问数据权限,并可以将多个函数声明写在同一个类中,调用只需使用 " 类名.函数名 “即可调用里面的函数
|
数据可视化 图形学 流计算
Unity 基础 之 代码动态监听UI交互组件汇总
通过介绍组件面板和代码示例,演示代码监听UI交互组件。
303 0
Unity 基础 之 代码动态监听UI交互组件汇总

热门文章

最新文章