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);
}
}
}
}

react video的更多相关文章

  1. React 基于antd+video.js实现m3u8格式视频播放及实时切换

    文档连接地址(官网看起麻烦,看中文别人整理好的)https://blog.csdn.net/a0405221/article/details/80923090 React项目使用  安装依赖 npm ...

  2. Redux React & Online Video Tutorials

    Redux React & Online Video Tutorials https://scrimba.com/@xgqfrms https://scrimba.com/c/cEwvKNud ...

  3. React Native 的ES5 ES6写法对照表

    模块 引用 在ES5里,如果使用CommonJS标准,引入React包基本通过require进行,代码类似这样: //ES5 var React = require("react" ...

  4. React Native开发技术周报2

    (1).资讯 1.React Native 0.22_rc版本发布 添加了热自动重载功能 (2).技术文章 1.用 React Native 设计的第一个 iOS 应用 我们想为用户设计一款移动端的应 ...

  5. React的第一步

    首先了解React中所牵扯到的几个重要的概念 什么是React? 是Facebook的开发团队开发出来的一个用于构建用户界面个js库,最近才开源出来公布于世,它的初衷是用于创建“独立的视图组件”,一个 ...

  6. React/React Native 的ES5 ES6写法对照表

    //es6与es5的区别很多React/React Native的初学者都被ES6的问题迷惑:各路大神都建议我们直接学习ES6的语法(class Foo extends React.Component ...

  7. React v16-alpha 从virtual dom 到 dom 源码简读

    一.物料准备 1.克隆react源码, github 地址:https://github.com/facebook/react.git 2.安装gulp 3.在react源码根目录下: $npm in ...

  8. 【React Native 实战】微信登录

    1.前言 在今天无论是游戏开发还是app开发,微信作为第三方登录必不可少,今天我们就用react-native-wechat实现微信登录,分享和支付同样的道理就不过多的介绍了. 2.属性 1)regi ...

  9. React Native视频播放(iOS)

    网站链接:http://www.ncloud.hk/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/learn-react-native-video/ React Nativ ...

  10. [React Native] Complete the Notes view

    In this final React Native lesson of the series we will finalize the Notes view component and squash ...

随机推荐

  1. 基于TDSQL-C对OOM问题进行优化

    OOM是实例使用内存超过实例规格内存上限导致进程被kill,实例存在秒级的不可用.MySQL的内存管理比较复杂,内存监控需要开启performance schema查询(默认关闭),会带来额外的内存消 ...

  2. java正则解析ip

    public class test { public static void main(String[] args) { // TODO Auto-generated method stub Stri ...

  3. 查找php-fpm

    [root@VM-4-6-centos /]# find / -name php-fpm/opt/remi/php74/root/usr/sbin/php-fpm/etc/opt/remi/php74 ...

  4. Dapper、EF、WebAPI转载记录

    轻量级框架Dapper基础 https://www.cnblogs.com/Sinte-Beuve/p/4231053.html   基本使用 https://www.cnblogs.com/hxzb ...

  5. TCP和UDP协议之间的区别与原理

    一.TCP和UDP协议之间的区别 TCP是基于连接的,而UDP是基于非连接的. TCP传输数据稳定可靠,适用于对网络通讯质量要求较高的场景,需要准确无误的传输给对方,比如,传输文件,发送邮件,浏览网页 ...

  6. HCIP-ICT实战进阶08-以太网链路的聚合和集群

    HCIP-ICT实战进阶08-以太网链路的聚合和集群 1 网络可靠性需求 网络可靠性可以从设备.链路多个层面实现, 保持当前设备或链路出现单点或者多点故障时保证网络服务不间断的能力. 网络可靠性 设备 ...

  7. linux基本命令说明参数

    linux基本命令说明参数 标签(空格分隔): Linux 1.# 表示权限用户(如:root),$ 表示普通用户 开机提示:Login:输入用户名 password:输入口令 用户是系统注册用户成功 ...

  8. Linux学习 --- 系统网络配置

    前言 : 如果一台计算机想接入互联网,必须配置好IP地址,子网掩码,网关,DNS服务器.在Linux系统中,这些信息都可以修改对应的配置文件来进行配置.临时配置一下网络可以使用一些简单的命令来进行配置 ...

  9. shell_Day07

    函数: 函数介绍function 为了避免代码重复使用,我们一般通过函数编写代码块,而这一个代码块用来实现某种功能,这个功能在后面的代码中,会重复调用: 函数的语法格式 function check_ ...

  10. ES-索引库

    数据准备 本次学习涵盖ES简单查询,聚合查询,所以在创建测试库时会可以涵盖一些个性化字段,用于学习搜索用法 索引创建 几个疑问 1.能否用中文命名 安排:我用"蓝闪test",中英 ...