<template>
<div class="custom-video_container"
ref="custom-video_container"
@mouseover="handleControls($event, 'start')"
@mouseleave="handleControls($event, 'end')">
<video
class="custom-video_video"
ref="custom-video"
:poster="videoOption.poster">
<p>设备不支持</p>
</video>
<!-- 控制区域背景 -->
<transition name="fade">
<div class="custom-video_control"
v-show="!videoState.hideControl || !videoState.play">
<div class="row1">
<!-- 进度条 -->
<div class="custom-video_control-bg"
@mouseleave="handlePrograssleave"
@mousedown="handlePrograssDown"
@mouseup="handlePrograssUp"
@mousemove="handlePrograssMove">
<div class="custom-video_control-bg-outside"
ref="custom-video_control-bg-outside">
<span
class="custom-video_control-bg-inside"
ref="custom-video_control-bg-inside">
</span>
<span
class="custom-video_control-bg-inside-point"
ref="custom-video_control-bg-inside-point"
></span>
</div>
</div>
</div>
<div class="row2">
<div class="row2-left">
<!--播放按钮-->
<div class="custom-video-play-container">
<span
class="custom-video_play custom-video_play-play icon_icon_video_paly"
@click="play('btn')">
</span>
<span
class="custom-video_play custom-video_play-pause icon_icon_video_suspend"
@click="pause('btn')">
</span>
</div>
<!-- 时间 -->
<div class="custom-video_control-time">
<span>{{currentTime ? currentTime : '00:00'}}</span>
/
<span>{{duration ? duration : '00:00'}}</span>
</div>
</div>
<div class="row2-right">
<!-- 声音 -->
<div class="custom-video_control-voice"
@click="handelShowMultiple('in')"
@mouseleave="handelShowMultiple('out')">
<span class="custom-video_control-voice-play icon_icon_VMS_Set-up">
倍数
</span>
<ul v-show="voideoMultiple">
<li @click="changeMultiple(0.75)"
:class="multipleIndex === 0.75 ? 'checkedMultiple': ''">0.75倍
</li>
<li @click="changeMultiple(1)"
:class="multipleIndex === 1 ? 'checkedMultiple': ''">1倍
</li>
<li @click="changeMultiple(2)"
:class="multipleIndex === 2 ? 'checkedMultiple': ''">2倍
</li>
</ul>
</div>
<!--截图-->
<div class="custom-video_control-voice"
@click="handleScreenShot">
<span class="custom-video_control-voice-play el-icon-camera-solid">
截图
</span>
</div>
<!-- 全屏缩放 -->
<span
class="custom-video_control-full icon_icon_video_lessen"
@click="handleScreen"
></span>
</div>
</div>
</div>
</transition>
</div>
</template>
<script>
import flvjs from 'flv.js'
import $http from '@/utils/$http'
export default {
name: 'videoRecordplayer',
props: ['item'],
data() {
return {
checkFull: false,
isRecord: true,
videoOption: {
// src: require("../../static/media/taru.mp4"), //视频
// poster: require("../../static/images/poster.jpg"), // 初始化占位图片
volume: 20
},
videoState: {
play: false, //播放状态
hideControl: false, // 控制栏状态
distance: 0, // 移动的距离
downState: false, // 鼠标点击进度条
playState: false,
leftInit: 0, // 当前进度初始偏移量
screenState: false
},
voiceState: { // 同上
distance: 0,
downState: false,
topInit: 0
},
videoDom: null, // video
videoProOut: null, // 视频总进度条
videoPro: null, // 视频进度条
videoPoi: null, // 视频进度点
duration: 0, // 视频总时长
currentTime: 0, // 视频当前播放时长
processWidth: 0, // 视频进度条总长度
voiceProOut: null, // 音频总进度条
voicePro: null, // 音频进度条
voicePoi: null, // 音频进度点
volProcessHeight: 0,
voideoMultiple: false, //播放倍数
multipleIndex: 1
}
},
created() {
// console.log(this.item)
window.addEventListener('resize', this.isFullScreen)
},
mounted() {
this.toScreen()
/*播放 流视频 的插件 如果是mp4格式 不需要 下载 - 引入 */
const videoDom = this.$refs['custom-video']
if (flvjs.isSupported) {
this.flvPlayer = flvjs.createPlayer({
type: 'flv',
hasAudio: false,
url: this.item.recordUrl
})
this.flvPlayer.attachMediaElement(videoDom)
this.flvPlayer.load()
this.flvPlayer.play()
// 初始化相关元数据
this.videoDom = this.$refs['custom-video']
this.videoProOut = this.$refs['custom-video_control-bg-outside']
this.videoPro = this.$refs['custom-video_control-bg-inside']
this.videoPoi = this.$refs['custom-video_control-bg-inside-point']
this.voiceProOut = this.$refs['custom-video_control-voice-bg-outside']
this.voicePro = this.$refs['custom-video_control-voice-bg-inside']
this.voicePoi = this.$refs['custom-video_control-voice-bg-point']
this.processWidth = this.videoProOut.clientWidth
this.videoDom.volume = this.videoOption.volume / 100 // 设置初始化声音
this.initMedaData()
}
},
methods: {
initMedaData() { // 初始化video相关事件
this.videoDom.addEventListener('loadedmetadata', () => { // 获取视频总时长
this.videoState.leftInit = this.getOffset(this.videoProOut).left
this.processWidth = this.videoProOut.clientWidth
if (this.videoDom.duration !== Infinity) {
this.duration = this.timeTranslate(this.videoDom.duration)
} else {
this.duration = '未知'
}
})
this.videoDom.addEventListener('click', () => { // 点击视频区域可以进行播放或者暂停
if (this.videoDom.paused || this.videoDom.ended) {
if (this.videoDom.ended) {
this.videoDom.currentTime = 0
}
this.play('btn')
} else {
this.pause('btn')
}
})
this.videoDom.addEventListener('timeupdate', () => { // 监听视频播放过程中的时间
const percentage = 100 * this.videoDom.currentTime / this.videoDom.duration
this.videoPro.style.width = percentage + '%'
this.videoPoi.style.left = percentage + '%'
this.currentTime = this.timeTranslate(this.videoDom.currentTime)
})
this.videoDom.addEventListener('ended', () => { // 监听结束播放事件
this.videoPro.style.width = 0
this.videoPoi.style.left = 0
this.currentTime = 0
this.videoState.play = false
this.videoState.hideControl = false
})
// this.videoDom.addEventListener('volumechange', () => {
// const percentage = this.videoDom.volume * 100
// this.voicePro.style.height = percentage + '%'
// this.voicePoi.style.bottom = percentage + '%'
// })
},
play(flag) { // 播放按钮事件
if (flag) this.videoState.playState = true
this.videoState.play = true
this.videoDom.play()
},
pause(flag) { // 暂停按钮事件
if (flag) this.videoState.playState = false
this.videoDom.pause()
this.videoState.play = false
},
handlePrograssDown(ev) { // 监听点击进度条事件,方便获取初始点击的位置
// 视频暂停
this.videoState.downState = true //按下鼠标标志
this.pause()
this.videoState.distance = ev.clientX - this.videoState.leftInit
},
handlePrograssMove(ev) { // 监听移动进度条事件,同步播放相关事件
if (!this.videoState.downState) return
let disX = ev.clientX - this.videoState.leftInit
if (disX > this.processWidth) {
disX = this.processWidth
}
if (disX < 0) {
disX = 0
}
this.videoState.distance = disX
this.videoDom.currentTime = this.videoState.distance / this.processWidth * this.videoDom.duration
},
handlePrograssleave() {
this.videoState.downState = false
},
handlePrograssUp() { //松开鼠标,播放当前进度条视频
this.videoState.downState = false
// 视频播放
this.videoDom.currentTime = 2
this.videoDom.currentTime = this.videoState.distance / this.processWidth * this.videoDom.duration
this.currentTime = this.timeTranslate(this.videoDom.currentTime)
// if (this.videoState.playState) {
// this.play()
// }
},
handleControls(ev, flag) { // 监听离开或者进入视频区域隐藏或者展示控制栏
switch (flag) {
case 'start':
this.videoState.hideControl = false
break
case 'end':
this.videoState.hideControl = true
break
default:
break
}
},
handleScreen() { // 退出
this.$emit('closeVideo')
},
timeTranslate(t) { // 时间转化
let m = Math.floor(t / 60)
m < 10 && (m = '0' + m)
return m + ':' + (t % 60 / 100).toFixed(2).slice(-2)
},
getOffset(node, offset) { // 获取当前屏幕下进度条的左偏移量和又偏移量
if (!offset) {
offset = {}
offset.left = 0
offset.top = 0
}
if (node === document.body || node === null) {
return offset
}
offset.top += node.offsetTop
offset.left += node.offsetLeft
return this.getOffset(node.offsetParent, offset)
},
//播放倍数
handelShowMultiple(type) {
if (type === 'in') this.voideoMultiple = true
else this.voideoMultiple = false
},
//设置速度
changeMultiple(speed) {
this.videoDom.playbackRate = speed
this.multipleIndex = speed
this.voideoMultiple = false
},
//全屏的方法
toScreen() {
// console.log("全屏功能");
let screenDom = this.$refs['custom-video_container']
//W3C
if (screenDom.requestFullscreen) {
screenDom.requestFullscreen()
}
//FireFox
else if (screenDom.mozRequestFullScreen) {
screenDom.mozRequestFullScreen()
}
//Chrome等
else if (screenDom.webkitRequestFullScreen) {
screenDom.webkitRequestFullScreen()
}
//IE11
else if (screenDom.msRequestFullscreen) {
screenDom.msRequestFullscreen()
}
}
,
isFullScreen() {
let isFull = document.isFullScreen || document.mozIsFullScreen || document.webkitIsFullScreen
// console.log(isFull)
if (!isFull) this.$emit('closeVideo')
}
,
// 截图
handleScreenShot() {
// const video = document.querySelector("#splitDom-1");
const video = this.$refs['custom-video']
const canvas = document.createElement('canvas')
const scale = 1
canvas.width = video.videoWidth * scale
canvas.height = video.videoHeight * scale
canvas
.getContext('2d')
.drawImage(video, 0, 0, canvas.width, canvas.height)
const base64src = canvas.toDataURL()
// console.log(base64src)
// 前端保存截图为jpg文件
let obj = {
'groupId': this.item.ipcGroupId,
'ipcId': this.item.ipcId,
'ipcName': `ZC-${this.item.recordId}-SCREENSHOT-${new Date().getTime()}`,
'recordId': '',
'streamUrl': base64src
}
$http.post('/manager/recording/storageScreenshots', obj).then(res => {
if (res.status == 200) {
this.$message({
showClose: true,
message: '截图保存成功',
type: 'success'
})
}
})
}
},
beforeDestroy() {
window.removeEventListener('resize', this.isFullScreen)
}
}
</script>
<style lang="scss" scoped>
/* 总容器 */
.custom-video_container {
width: 500px;
height: 300px;
margin: 0 auto;
position: relative;
overflow: hidden;
}
/* 视频标签 */
.custom-video_video {
width: 100%;
height: 100%;
object-fit: fill;
}
.custom-video-play-container {
width: 100px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
/* 暂停 或者 播放 */
.custom-video_play {
display: inline-block;
width: 50%;
text-align: center;
color: #f0f0f0;
}
/*!* 暂停隐藏 *!*/
/*.custom-video_play-pause {*/
/*display: none;*/
/*}*/
/*!* hover 显示 *!*/
/*.custom-video_container:hover > .custom-video_play-pause {*/
/*display: inline-block;*/
/*}*/
/* hover 播放按钮动画 */
.custom-video_play:hover {
box-shadow: 0 0 10px #5A4180;
transition: all 0.4s;
}
/* 控制栏 */
.custom-video_control {
position: absolute;
width: 100%;
left: 0;
bottom: 0;
background-color: rgba(0, 0, 0, .55);
display: flex;
flex-direction: column;
justify-content: space-between;
}
.row1 {
height: 32px;
}
.row2 {
height: 26px;
display: flex;
justify-content: space-between;
padding-bottom: 10px;
}
.row2-left,
.row2-right {
display: flex;
}
/* 控制栏进度条 */
.custom-video_control-bg {
flex: 1;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
margin: 0 10px;
}
/* 控制栏进度条 —— 总长度 */
.custom-video_control-bg-outside {
width: 100%;
height: 5px;
border-radius: 2.5px;
background-color: #aaa;
position: relative;
cursor: pointer;
}
/* 控制栏进度条 —— 播放长度 */
.custom-video_control-bg-inside {
position: absolute;
display: inline-block;
width: 0;
height: 100%;
border-radius: 2.5px;
left: 0;
top: 0;
background-color: #fff;
transition: all 0.2s;
}
/* 控制栏进度条 —— 播放点 */
.custom-video_control-bg-inside-point {
display: inline-block;
width: 10px;
height: 10px;
background-color: #fff;
border-radius: 50%;
position: absolute;
top: -2.5px;
left: -1%;
transition: all 0.2s;
}
/* 控制栏 —— 声音、时间、全屏缩放 */
.custom-video_control-voice,
.custom-video_control-time,
.custom-video_control-full {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
color: #fff;
position: relative;
height: 100%;
}
.custom-video_control-voice:hover > .custom-video_control-voice-bg {
display: block;
}
.custom-video_control-voice-play {
z-index: 10;
}
.custom-video_control-voice-bg {
display: none;
position: absolute;
width: 30px;
height: 100px;
background-color: rgba(0, 0, 0, .55);
left: 0;
bottom: 0px;
border-radius: 15px;
}
.custom-video_control-voice-bg-outside {
width: 5px;
height: 70px;
border-radius: 2.5px;
background-color: #aaa;
position: absolute;
left: 50%;
transform: translate3d(-50%, 10%, 0);
cursor: pointer;
}
.custom-video_control-voice-bg-inside {
display: inline-block;
position: absolute;
width: 100%;
bottom: 0;
left: 0;
border-radius: 2.5px;
background-color: #fff;
height: 0;
}
.custom-video_control-voice-bg-point {
display: inline-block;
width: 10px;
height: 10px;
background-color: #fff;
border-radius: 50%;
position: absolute;
left: -2.5px;
bottom: -1px;
}
.custom-video_control-time {
font-size: 12px;
}
.custom-video_control-full {
font-size: 14px;
}
.custom-video_control-voice,
.custom-video_control-full {
/*width: 30px;*/
height: 30px;
margin: 0 10px;
cursor: pointer;
}
/* 控制栏隐藏动画 */
.fade-enter-active {
transition: all .3s ease;
}
.fade-leave-active {
transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.fade-enter, .fade-leave-to {
transform: translateY(50px);
opacity: 0;
}
/* 倍数 */
ul {
position: absolute;
bottom: 25px;
width: 100%;
text-align: center;
background: rgba(255, 255, 255, 0.1);
border-radius: 4px;
padding: 0 10px;
}
ul > li {
height: 35px;
line-height: 35px;
}
.checkedMultiple {
color: #328cfa;
}
</style>
vue-cli中自定义播放器样式
最新推荐文章于 2024-04-29 14:57:10 发布