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

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

前言:


我是用的原生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>
相关文章
|
3月前
|
编解码 前端开发 vr&ar
从零开始的PICO教程(4)--- UI界面绘制与响应事件
这篇文章是PICO开发系列教程的第四部分,主要介绍了如何在PICO 4 VR环境中创建UI界面,包括Canvas和Panel的配置、UI元素的绘制、以及Button和Slider的事件响应绑定,并通过示例展示了数字增减和滑块功能的具体实现。
从零开始的PICO教程(4)--- UI界面绘制与响应事件
|
4月前
|
JavaScript
vue + element UI【实战】音乐播放器/语音条(内含音频的加载、控制,事件监听,信息获取,手机网页阴影的去除等技巧)
vue + element UI【实战】音乐播放器/语音条(内含音频的加载、控制,事件监听,信息获取,手机网页阴影的去除等技巧)
70 1
|
小程序 开发者
wepy框架-触摸内容滑动组件使用步骤
wepy框架-触摸内容滑动组件使用步骤
45 0
[虚幻引擎插件介绍] DTGlobalEvent 蓝图全局事件, Actor, UMG 相互回调,自由回调通知事件函数,支持自定义参数。
本插件可以在虚幻的蓝图 Actor, Obiect,UMG 里面指定绑定和执行消息,可带自定义参数。 参数支持 Bool,Byte,Int,Int64,Float,Name,String,Text,Vector,Rotator,Transform,Object,Actor。
87 0
|
小程序 JavaScript 前端开发
小程序封装加载动画
在小程序的开发中,页面的加载过程可能会因为网络状况的不好或数据量的过大而显得非常缓慢,这时候加上一个加载动画就能有效的缓解用户的等待焦虑感。而对于应用的多个页面来说,使用全局加载动画可以提高用户体验,让应用显得更加美观和专业。本篇技术分享博客将为大家介绍在小程序中封装全局加载动画的具体实现步骤,帮助您提高小程序的用户体验。通过上述步骤,我们就完成了小程序中封装全局加载动画的具体实现方法。在实际开发中,我们可以根据实际需求对组件样式和方法进行调整和修改,以满足不同的开发需求。
239 0
|
JavaScript 小程序
UniApp 小程序封装原生组件(使用与交互详细流程)
UniApp 小程序封装原生组件(使用与交互详细流程)
419 0
|
Java Maven Android开发
Android组件化开发(六)-- 短视频播放组件封装
前面几篇文章我们封装了几个组件化功能组件: 包括:`网络请求组件`,`图片加载请求组件`,`应用保活组件`,`音乐播放组件封装`。 > 每个组件都可以直接拿到自己项目中使用,当然还需根据自己项目要求进行优化。
|
程序员
回调函数实现四则运算器(可增添功能)
本文讲解:回调函数实现四则运算器(可增添功能)
|
前端开发 API UED
「前端UI组件」如何实现一个骨架屏组件
用技术实现梦想,用梦想打开前端技术之门。今天分享如何实现一个骨架屏组件。
758 1
「前端UI组件」如何实现一个骨架屏组件
|
小程序 前端开发 JavaScript
【小程序开发】—— 封装自定义弹窗组件
【小程序开发】—— 封装自定义弹窗组件
193 0
【小程序开发】—— 封装自定义弹窗组件