import React, { useRef, useState, useCallback } from 'react';

import './style.scss';
const typeCheckFactory = (typeName: string) => {
return (arg: any) => {
if (typeof arg == typeName) {
return true;
} else {
return false;
}
};
};
export const isNumber = typeCheckFactory('number') as (
arg: any,
) => arg is number;
function setUnit(value: string | number) {
return isNumber(value)
? value + 'px'
: ~value.indexOf('%') || !/^\d+$/.test(value)
? value
: value + 'px';
}
function zeroFill(num: number) {
if (num < 10) {
return '0' + num;
}
return num;
} const timerTarget: { bufferTimer: NodeJS.Timeout | null } = {
bufferTimer: null,
};
export default function(props: {
height: number | string;
width: number | string;
url: string;
coverImage: string;
}) {
const videoHeight = setUnit(props.height);
const videoWidth = setUnit(props.width);
const target = useRef<HTMLVideoElement>(null);
// 0 play, 1 stop, 2 refresh
const [videoState, setVideoState] = useState<0 | 1 | 2>(0);
// 声音
const [voice, setVoice] = useState<1 | 0>(0);
// 当前时间
const [currentTime, setCurrentTime] = useState<string | number>(`00:00`);
// 进度
const [progress, setProgress] = useState<string | number>(0);
// 播放完成 1代表完成
const [over, setOver] = useState<1 | 0>(0);
function play() {
target.current && target.current.play();
}
function pause() {
target.current && target.current.pause();
}
const toggle = useCallback(
function(jump = false) {
if (
(videoState == 0 || over == 1 || jump) &&
target &&
target.current
) {
const current = target.current;
if (over == 1 && !jump) {
setProgress(0);
setOver(0);
current.currentTime = 0;
}
play();
setVideoState(1);
timerTarget.bufferTimer = setInterval(function() {
const pgs = current.currentTime / current.duration;
if (pgs == 1) {
timerTarget.bufferTimer &&
clearInterval(timerTarget.bufferTimer);
setOver(1);
}
setProgress(pgs * 100 + '%');
}, 1000 / 30);
} else {
timerTarget.bufferTimer &&
clearInterval(timerTarget.bufferTimer);
pause();
setVideoState(0);
}
},
[over, videoState],
); function toggleVoice(): void {
setVoice((v) => (1 - v) as 1 | 0);
} // 处理秒数为时分秒 h:m:s
function getTime(num: number) {
const m = zeroFill(Math.floor(num / 60)),
remainder = zeroFill(Math.floor(num % 60)),
time = m + ':' + remainder;
return time;
}
function progressClick(e: React.MouseEvent<HTMLDivElement, MouseEvent>) {
e.stopPropagation();
const currentTarget = e.currentTarget;
const barLength = e.pageX - currentTarget.offsetLeft;
timerTarget.bufferTimer && clearInterval(timerTarget.bufferTimer); if (target.current) {
target.current.currentTime =
(barLength / currentTarget.clientWidth) *
target.current.duration;
setProgress((barLength / currentTarget.clientWidth) * 100 + '%');
toggle(true);
}
}
return (
<div
className="jdw-video"
style={{ height: videoHeight, width: videoWidth }}
>
<div
className="mask"
onClick={() => {
toggle(false);
}}
>
{videoState == 0 && <div className="play"></div>}
{videoState == 1 && (
<div
className="toolbar"
onClick={(e) => e.stopPropagation()}
>
<span
className="pause"
onClick={() => toggle(false)}
></span>
<div className="progress" onClick={progressClick}>
<div
className="bar"
style={{ width: progress }}
></div>
</div>
<span className="timer">
{currentTime}/
{getTime(
target && target.current
? target.current.duration
: 0,
)}
</span>
<span
className={voice ? 'mute' : 'speak'}
onClick={toggleVoice}
></span>
</div>
)}
</div>
<video
poster={props.coverImage}
ref={target}
height={props.height}
width={props.width}
muted={!!voice}
onTimeUpdate={() => {
setCurrentTime(
getTime(
target && target.current
? target.current.currentTime
: 0,
),
);
}}
>
<source src={props.url} type="video/ogg" />
Your browser does not support the video tag.
</video>
</div>
);
}
.video {
position: relative;
video {
position: relative;
z-index: 0;
}
.mask {
box-sizing: border-box;
cursor: pointer;
height: 100%;
position: absolute;
width: 100%;
z-index: 11; .item {
background-position: left top;
background-repeat: no-repeat;
background-size: cover;
border-radius: 50%;
height: 22px;
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
width: 22px;
}
.play {
@extend .item;
background-image: url(./images/play.png);
}
.refresh {
@extend .item;
background-image: url(./images/refresh.png);
}
.toolbar {
align-items: center;
bottom: 0;
display: flex;
height: 48px;
justify-content: space-between;
left: 20px;
position: absolute;
right: 20px;
.pause {
background: url(./images/pause.png) no-repeat center center;
background-size: 12px 12px;
cursor: pointer;
height: 48px;
margin-right: 24px;
width: 48px;
}
.progress {
cursor: pointer;
flex-grow: 1;
flex-shrink: 1;
height: 12px;
margin-right: 24px;
position: relative;
&:before {
background-color: rgba(255, 255, 255, 0.3);
border-radius: 4px;
content: '';
height: 4px;
left: 0;
position: absolute;
top: 4px;
width: 100%;
}
.bar {
height: 12px;
min-width: 12px;
position: relative;
&:before {
background-color: #ffffff;
border-radius: 50%;
content: '';
height: 12px;
position: absolute;
right: 0;
top: 0;
width: 12px;
z-index: 2;
}
&:after {
background-color: rgba(242, 23, 12, 1);
border-radius: 4px;
content: '';
height: 4px;
left: 0;
position: absolute;
top: 4px;
width: 100%;
}
}
}
.timer {
color: rgba(255, 255, 255, 1);
font-size: 20px;
height: 48px;
line-height: 48px;
margin-right: 24px;
min-width: 115px;
}
.voice {
background-position: center center;
background-repeat: no-repeat;
background-size: 24px 24px;
cursor: pointer;
height: 48px;
width: 48px;
}
.mute {
@extend .voice;
background-image: url(./images/mute.png);
}
.speak {
@extend .voice;
background-image: url(./images/voice.png);
}
}
}
}

最新文章

  1. Unity Animation System(动画系统)
  2. AspNetPager分页控件配置
  3. VS2012 提示未找到与约束 ContractName 匹配的倒出
  4. java io流之字节流
  5. Android基于mAppWidget实现手绘地图(十一)–移动地图到某个坐标
  6. java.lang.IllegalArgumentException 不合法的参数异常
  7. C# 杂项
  8. oracle行转列(连接字符串函数)
  9. sublimeText OmniMarkupPreviewer 404
  10. 支付宝修改回调地址后 issign=false
  11. FullPage.js全屏滚动插件的配置项、方法和回调函数
  12. UML进行Linux内核调试
  13. 解决WIN7上 SQL2008r2 由于防火墙问题 客户端无法远程连接的问题
  14. cout输出各种进制
  15. C#研究OpenXML之路(2-DocumentFormat.OpenXml命名空间)
  16. display的属性值测试
  17. 自定义 绑定响应函数 解除响应函数 .addEventListener 兼容 .attachEvent
  18. flink架构介绍
  19. [代码审计]某开源商城前台getshell
  20. Ubuntu12.04 Skype4.2 提示Skype can&#39;t connect,安装Skype4.3

热门文章

  1. 洛谷 P6021 洪水
  2. Linux环境使用Docker安装SqlServer2017
  3. 【随手记】Burp Suite 设置HTTP2
  4. js动态删除添加一行
  5. flutter SliverPersistentHeader子组件透明度渐变【滑动悬停appbar添加自定义组件的透明度】
  6. Linux下添加启动项并简化操作命令-nginx为例
  7. python_test_5001_Moudle_pandas
  8. laravel phpstorm ide-helper
  9. Python使用pip安装第三方模块问题
  10. py10函数之嵌套-名称空间作用域