master
lgf 3 years ago
parent 56b5df1d4b
commit 3c93cc1056
  1. 2
      src/appComponent.tsx
  2. 31
      src/core/context/index.ts
  3. 18
      src/core/controller/index.tsx
  4. 9
      src/core/controls/index.tsx
  5. 16
      src/core/index.tsx
  6. 7
      src/core/progress/index.tsx
  7. 99
      src/core/useVideo.ts
  8. 26
      src/interface/index.ts
  9. 1
      src/utils/useWindowClient.ts

@ -6,7 +6,7 @@ const AppComponent = memo(function AppComponent(props) {
return ( return (
<> <>
<JoLPlayer /> <JoLPlayer />
{/* <JoLPlayer /> */} <JoLPlayer />
</> </>
); );
}); });

@ -1,32 +1,43 @@
import React, { useReducer } from 'react'; import React, { useReducer } from 'react';
export interface VideoStateType<K = boolean> { export interface VideoStateType<K = boolean, T = number> {
/** /**
* @description * @description
*/ */
isControl: K; isControl: K;
/**
* @description
*/
currentTime: T;
/**
* @description
*/
isPlay: K;
} }
/** /**
* @description * @description
*/ */
export interface contextType extends VideoStateType { export interface contextType {
videoRef: HTMLVideoElement | null; videoRef: HTMLVideoElement | null;
videoContainerRef: HTMLElement | null; videoContainerRef: HTMLElement | null;
lightOffMaskRef: HTMLElement | null; lightOffMaskRef: HTMLElement | null;
dispatch?: React.Dispatch<mergeAction>; dispatch?: React.Dispatch<mergeAction>;
videoFlow: VideoStateType;
} }
/** /**
* @description * @description
*/ */
export const initialState = { export const initialState = {
isControl: false, isControl: false,
currentTime: 0,
isPlay: false,
}; };
export const defaultValue = { export const defaultValue = {
videoRef: null, videoRef: null,
videoContainerRef: null, videoContainerRef: null,
lightOffMaskRef: null, lightOffMaskRef: null,
...initialState, videoFlow: initialState,
}; };
export const FlowContext = React.createContext<contextType>(defaultValue); export const FlowContext = React.createContext<contextType>(defaultValue);
@ -34,13 +45,25 @@ export interface isControlActionType {
type: 'isControl'; type: 'isControl';
data: VideoStateType['isControl']; data: VideoStateType['isControl'];
} }
export type mergeAction = isControlActionType; export interface currentTimeActionType {
type: 'currentTime';
data: VideoStateType['currentTime'];
}
export interface isPlayActionType {
type: 'isPlay';
data: VideoStateType['isPlay'];
}
export type mergeAction = isControlActionType | currentTimeActionType | isPlayActionType;
export const useVideoFlow = () => { export const useVideoFlow = () => {
const reducer = (state: VideoStateType, action: mergeAction) => { const reducer = (state: VideoStateType, action: mergeAction) => {
switch (action.type) { switch (action.type) {
case 'isControl': case 'isControl':
return { ...state, isControl: action.data }; return { ...state, isControl: action.data };
case 'currentTime':
return { ...state, currentTime: action.data };
case 'isPlay':
return { ...state, isPlay: action.data };
default: default:
return state; return state;
} }

@ -15,7 +15,20 @@ const Index = memo(function Index(props) {
const { dispatch } = reviceProps; const { dispatch } = reviceProps;
const { isPlay, handleChangePlayState } = useVideo(reviceProps.videoRef); const { isPlay, handleChangePlayState, currentTime } = useVideo({
onPause: (val: any) => {
console.log(val);
},
onPlay: (val: any) => {
console.log(val);
},
onTimeChange: (val: any) => {
// console.log(val);
},
onEndEd: (val: any) => {
console.log('结束', val);
},
});
const timer = useRef<NodeJS.Timeout | null>(null!); const timer = useRef<NodeJS.Timeout | null>(null!);
@ -39,7 +52,6 @@ const Index = memo(function Index(props) {
*/ */
const showControl = (e: any, status: string) => { const showControl = (e: any, status: string) => {
dispatch!({ type: 'isControl', data: status === 'enter' ? true : false }); dispatch!({ type: 'isControl', data: status === 'enter' ? true : false });
return false;
}; };
/** /**
* @description * @description
@ -48,6 +60,7 @@ const Index = memo(function Index(props) {
if (timer.current) { if (timer.current) {
clearInterval(timer.current); clearInterval(timer.current);
} }
timer.current = setInterval(() => { timer.current = setInterval(() => {
setPre(viewClientX.current); setPre(viewClientX.current);
/** /**
@ -68,6 +81,7 @@ const Index = memo(function Index(props) {
clearInterval(timer.current); clearInterval(timer.current);
} }
}; };
return ( return (
<div <div
className="controller-container" className="controller-container"

@ -30,9 +30,7 @@ const Index = memo(function Index(props) {
const revicePropsData = useRef<any>(); const revicePropsData = useRef<any>();
const { isPlay, handleChangePlayState, currentTime, duration, isPictureinpicture } = useVideo( const { isPlay, handleChangePlayState, currentTime, duration, isPictureinpicture } = useVideo({});
reviceProps.videoRef,
);
const { controlsState, dispatch } = useControls(); const { controlsState, dispatch } = useControls();
@ -193,7 +191,10 @@ const Index = memo(function Index(props) {
} }
}; };
return ( return (
<div className="controls-container" style={{ opacity: reviceProps.isControl ? '1' : '0' }}> <div
className="controls-container"
style={{ opacity: reviceProps.videoFlow!.isControl ? '1' : '0' }}
>
<MonitorComponent <MonitorComponent
isPlay={isPlay} isPlay={isPlay}
handleChangePlayState={handleChangePlayState} handleChangePlayState={handleChangePlayState}

@ -92,12 +92,16 @@ const Index = memo(function Index({
}, [videoSrc]); }, [videoSrc]);
const contextProps = useMemo(() => { const contextProps = useMemo(() => {
return Object.assign({}, videoFlow, { return Object.assign(
videoRef: videoRef.current, {},
videoContainerRef: videoContainerRef.current, {
lightOffMaskRef: lightOffMaskRef.current, videoRef: videoRef.current,
dispatch, videoContainerRef: videoContainerRef.current,
}); lightOffMaskRef: lightOffMaskRef.current,
dispatch,
videoFlow,
},
);
}, [videoRef.current, videoFlow]); }, [videoRef.current, videoFlow]);
return ( return (

@ -29,7 +29,7 @@ const Index = memo(function Index(props) {
const reviceProps = useContext(FlowContext); const reviceProps = useContext(FlowContext);
const { currentTime, duration, bufferedTime } = useVideo(reviceProps.videoRef); const { currentTime, duration, bufferedTime } = useVideo({});
const { progressState, dispatch } = useProgress(); const { progressState, dispatch } = useProgress();
@ -163,7 +163,10 @@ const Index = memo(function Index(props) {
}; };
return ( return (
<div className="progress-container" style={{ opacity: reviceProps.isControl ? '1' : '0' }}> <div
className="progress-container"
style={{ opacity: reviceProps.videoFlow!.isControl ? '1' : '0' }}
>
<div className="progress-bg" ref={progressBgRef}> <div className="progress-bg" ref={progressBgRef}>
<div className="progress-buffered" style={{ width: `${calculateBufferedPercent}%` }}></div> <div className="progress-buffered" style={{ width: `${calculateBufferedPercent}%` }}></div>
<div <div

@ -1,96 +1,115 @@
import { useRef, useMemo, useEffect, useState, useReducer, useContext } from 'react'; import { useRef, useMemo, useEffect, useState, useReducer, useContext, useCallback } from 'react';
import useMandatoryUpdate from '@/utils/useMandatoryUpdate'; import useMandatoryUpdate from '@/utils/useMandatoryUpdate';
import { FlowContext } from '@/core/context'; import { FlowContext } from '@/core/context';
export const useVideo = (videoEle: HTMLVideoElement | null) => { export const useVideo = ({ onPause, onPlay, onTimeChange, onEndEd }: any) => {
const forceUpdate = useMandatoryUpdate(); const forceUpdate = useMandatoryUpdate();
const reviceProps = useContext(FlowContext); const reviceProps = useContext(FlowContext);
const videoRef = useRef<HTMLVideoElement | null>(null); const { videoRef: videoEle, dispatch, videoFlow } = reviceProps;
const [isPlay, setIsPlay] = useState<boolean>(false);
const [currentTime, setCurrentTime] = useState<number>(0);
const [duration, setDuration] = useState<number>(0); const videoParameter = useRef<any>({
isPlay: false,
currentTime: 0,
duration: 0,
bufferedTime: 0,
isPictureinpicture: false,
});
const [bufferedTime, setBufferedTime] = useState<number>(0); const videoRef = useRef<HTMLVideoElement | null>(null);
const [isPictureinpicture, setIsPictureinpicture] = useState<boolean>(false);
const interval = useRef<any>(null); const interval = useRef<NodeJS.Timeout | null>(null!);
videoRef.current = videoEle; videoRef.current = videoEle;
useEffect(() => { useEffect(() => {
// forceUpdate();
if (videoRef.current) { if (videoRef.current) {
/** /**
* @description * @description
*/ */
videoRef.current.addEventListener('canplay', () => { videoRef.current.addEventListener('canplay', () => {
setDuration(videoRef.current!.duration); videoParameter.current = {
...videoParameter.current,
duration: videoRef.current!.duration,
};
}); });
/** /**
* @description * @description
*/ */
videoRef.current.addEventListener('progress', () => { videoRef.current.addEventListener('progress', () => {
if (videoRef.current!.buffered.length >= 1) { if (videoRef.current!.buffered.length >= 1) {
setBufferedTime(videoRef.current!.buffered.end(0)); videoParameter.current = {
...videoParameter.current,
bufferedTime: videoRef.current!.buffered.end(0),
};
} }
}); });
/** /**
* @description * @description
*/ */
videoRef.current.addEventListener('enterpictureinpicture', () => { videoRef.current.addEventListener('enterpictureinpicture', () => {
setIsPictureinpicture(true); videoParameter.current = {
...videoParameter.current,
isPictureinpicture: true,
};
}); });
/** /**
* @description 退 * @description 退
*/ */
videoRef.current.addEventListener('leavepictureinpicture', () => { videoRef.current.addEventListener('leavepictureinpicture', () => {
setIsPictureinpicture(false); videoParameter.current = {
...videoParameter.current,
isPictureinpicture: false,
};
}); });
// 定时器用于更新当前视频时间 // 定时器用于更新当前视频时间
interval.current = setInterval(() => { interval.current = setInterval(() => {
setIsPlay(videoRef.current!.paused ? false : true); /**
setCurrentTime(videoRef.current!.currentTime); *
*/
forceUpdate();
videoParameter.current = {
...videoParameter.current,
currentTime: videoRef.current!.currentTime,
isPlay: videoRef.current!.paused ? false : true,
};
}, 1); }, 1);
videoRef.current.addEventListener('pause', () => playChange('pause')); videoRef.current.addEventListener('pause', pauseChange);
videoRef.current.addEventListener('play', () => playChange('play')); videoRef.current.addEventListener('play', playChange);
videoRef.current.addEventListener('timeupdate', timeupdate); videoRef.current.addEventListener('timeupdate', timeupdate);
videoRef.current.addEventListener('ended', endedChange);
} }
return () => { return () => {
interval.current && clearInterval(interval.current); interval.current && clearInterval(interval.current);
}; };
}, [videoEle, videoRef.current]); }, [videoEle, videoRef.current]);
const playChange = (status: string) => { const pauseChange = () => {
// console.log(`status`, status); onPause && onPause(videoParameter.current);
};
const playChange = () => {
onPlay && onPlay(videoParameter.current);
}; };
const timeupdate = () => { const timeupdate = () => {
// console.log(`2222222`, videoRef.current!.currentTime); onTimeChange && onTimeChange(videoParameter.current);
};
const endedChange = () => {
onEndEd && onEndEd(videoParameter.current);
}; };
const handleChangePlayState = () => { const handleChangePlayState = () => {
setIsPlay((pre) => { if (videoParameter.current.isPlay) {
if (isPlay) { videoRef.current!.pause();
videoRef.current!.pause(); } else {
} else { videoRef.current!.play();
videoRef.current!.play(); }
} videoParameter.current = {
return !pre; ...videoParameter.current,
}); isPlay: videoRef.current!.paused ? false : true,
};
}; };
return { return {
isPlay,
setIsPlay,
handleChangePlayState, handleChangePlayState,
currentTime, ...videoParameter.current,
duration,
bufferedTime,
isPictureinpicture,
}; };
}; };

@ -1,10 +1,4 @@
import React from 'react'; import React from 'react';
export interface videoOption {
width: number;
height: number;
}
export interface hoverShowStyleType { export interface hoverShowStyleType {
height: number; height: number;
opacity: number; opacity: number;
@ -12,11 +6,29 @@ export interface hoverShowStyleType {
progressBgRefEle: HTMLDivElement; progressBgRefEle: HTMLDivElement;
progressScrubberRefEle: HTMLDivElement; progressScrubberRefEle: HTMLDivElement;
} }
export interface videoOption {
/**
* @description width
*/
width: number;
/**
* @description height
*/
height: number;
/**
* @description
*/
theme?: string;
/**
* @description
*/
videoSrc: string;
}
export interface videoparameter { export interface videoparameter {
style?: React.CSSProperties; style?: React.CSSProperties;
/** /**
* @description * @description
*/ */
option: videoOption; option: videoOption;
className?: string;
} }

@ -1,5 +1,4 @@
import { useState, useEffect, useRef } from 'react'; import { useState, useEffect, useRef } from 'react';
import usePrevious from './usePrevious';
export interface useWindowSizeType { export interface useWindowSizeType {
clientX: number; clientX: number;
clientY: number; clientY: number;

Loading…
Cancel
Save