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. Linux修改开机图形/etc/motd

    修改 /etc/motd vim /etc/motd 植入图形 .--, .--, ( ( \.---./ ) ) '.__/o o\__.' {= ^ =} > - < / \ // \ ...

  2. blob对象excel文件上传下载

    页面结构 <el-upload style="width: 93%" action="/stap/systemManage/weakPassword/excelIm ...

  3. React Navite环境搭建

    俗话说"工欲善其事,必先利其器."所以,我们第一步就是搭建React Native开发坏境. 一.安装Node.js.npm.yarn 1.1 React native需要借助no ...

  4. 肖sir___整理 电商详解__拼团活动

    电商平台营销活动设计--拼团活动设计 2022-11-29 18:02 拼团是指一定数量的消费者在规定时间内,组织成团,并因人数优势而获取额外优惠或其他利益的一种形式 一.简介 拼团作为一种营销活动, ...

  5. npm发布和修改详细教程

    登录 登录npm账号(没有账号需要先前往npm注册 https://www.npmjs.com/) npm login npm notice Log in on https://registry.np ...

  6. VUE+Element+若依随笔001:点击左侧菜单跳转外部链接配置并传参数

    一.后台菜单配置部分:1.菜单管理中:新增父级目录2.配置内容: 菜单名称:测试用菜单 菜单路径:https://www.baidu.com/ 此处需要配置要跳转你的外部链接 组件名称:testMen ...

  7. 下载接口时出现:Try to run this command from the system terminal. Make sure that you use the correct version of 'pip' installed for your Python interpreter located at 'D:\python\demo\venv\Scripts\...的错误

    下载接口时出现:Try to run this command from the system terminal. Make sure that you use the correct version ...

  8. 利用Opencv+Python 实现二维码识别

    pip3 install pyzbar   准备工作: 二维码图片,我这里直接打印在了一张A4纸上,或者直接在草料网站上生成 草料二维码生成器,存放在手机上进行显示.在安装条码扫描库的时候大家注意:z ...

  9. vs MFC c++ rc文件的dilog打不开,显示加载失败

    最近在做一个项目,在vs2012上面用mfc画界面,由于没有确定好且不熟悉这个架构,控件类型变了又变,本人又是个有点强迫症的性格所以删掉了一些不用的控件,导致的结果就是上面说的,dialog打不开报加 ...

  10. GIT Authentication failed for错误问题处理

    1. Settings ==> Developer settings ==> Personal access tokens ==> Generate new token   生成新的 ...