From eb5b02f4c2db6be5403c6692646a4fe18428724f Mon Sep 17 00:00:00 2001 From: lgf <18827634408@163.com> Date: Mon, 9 Aug 2021 18:01:38 +0800 Subject: [PATCH] add declaration --- src/appComponent.tsx | 26 ++++++++-- src/core/config/index.ts | 2 + src/core/context/index.ts | 41 ++++++---------- src/core/controls/multiple.tsx | 11 +++-- src/core/controls/volume.tsx | 15 ++++-- src/core/index.scss | 4 +- src/core/index.tsx | 87 +++++++++++++--------------------- src/core/progress/index.tsx | 12 +++-- src/core/useVideo.ts | 22 ++++++--- src/core/useVideoCallback.ts | 51 ++++++++++++++++---- src/interface/index.ts | 75 ++++++++++++++++++++++++++++- 11 files changed, 234 insertions(+), 112 deletions(-) diff --git a/src/appComponent.tsx b/src/appComponent.tsx index 808c4f9..32504e2 100644 --- a/src/appComponent.tsx +++ b/src/appComponent.tsx @@ -6,8 +6,11 @@ import '@/icons/'; const AppComponent = memo(function AppComponent(props) { const videoRef = useRef(null!); - const onProgressSlide = (val: any) => { - console.log(`val`, val); + const onProgressMouseDown = (val: any) => { + // console.log(`val`, val); + }; + const onProgressMouseUp = (val: any) => { + console.log(`onProgressMouseUp`, val); }; const onPlay = (val: any) => { console.log(`播放`, val); @@ -16,20 +19,35 @@ const AppComponent = memo(function AppComponent(props) { console.log(`暂停`, val); }; const onTimeChange = (val: any) => { - console.log(`onTimeChange`, val); + // console.log(`onTimeChange`, val); }; const onEndEd = (val: any) => { console.log(`onEndEd`, val); }; + const onError = () => { + console.log(`onError`); + }; + const onvolumechange = (val: any) => { + console.log(`onvolumechange`, val); + }; return ( <> {/* */} diff --git a/src/core/config/index.ts b/src/core/config/index.ts index b929cc6..d7eb579 100644 --- a/src/core/config/index.ts +++ b/src/core/config/index.ts @@ -6,3 +6,5 @@ export const multipleList = [ { id: 1.5, name: '1.5x' }, { id: 2, name: '2.0x' }, ]; + +export const defaultTheme: string = 'blue'; diff --git a/src/core/context/index.ts b/src/core/context/index.ts index 4a110ff..f1d9806 100644 --- a/src/core/context/index.ts +++ b/src/core/context/index.ts @@ -1,22 +1,18 @@ import React, { useReducer } from 'react'; - +import { videoOption } from '@/interface'; export interface VideoStateType { /** * @description 是否显示控件 */ isControl: K; /** - * @description 视频当前时间 - */ - currentTime: T; - /** - * @description 是否播放 + * @description onProgressMouseDown事件的变化数据,用来区分是onProgressMouseDown事件触发的 */ - isPlay: K; + progressSliderChangeVal: T; /** - * @description onProgressSlider事件的变化数据,用来区分是onProgressSlider事件触发的 + * @description onProgressMouseUp事件的变化数据,用来区分是onProgressMouseUp事件触发的 */ - progressSliderChangeVal: T; + progressMouseUpChangeVal: T; } /** * @description 永不变的数据 @@ -27,15 +23,15 @@ export interface contextType { lightOffMaskRef: HTMLElement | null; dispatch?: React.Dispatch; videoFlow: VideoStateType; + propsAttributes?: videoOption; } /** * @description 变化的数据 */ export const initialState = { isControl: false, - currentTime: 0, - isPlay: false, progressSliderChangeVal: 0, + progressMouseUpChangeVal: 0, }; export const defaultValue = { @@ -50,35 +46,28 @@ export interface isControlActionType { type: 'isControl'; data: VideoStateType['isControl']; } -export interface currentTimeActionType { - type: 'currentTime'; - data: VideoStateType['currentTime']; -} -export interface isPlayActionType { - type: 'isPlay'; - data: VideoStateType['isPlay']; -} export interface progressSliderChangeValActionType { type: 'progressSliderChangeVal'; data: VideoStateType['progressSliderChangeVal']; } +export interface progressMouseUpChangeValValActionType { + type: 'progressMouseUpChangeVal'; + data: VideoStateType['progressMouseUpChangeVal']; +} export type mergeAction = | isControlActionType - | currentTimeActionType - | isPlayActionType - | progressSliderChangeValActionType; + | progressSliderChangeValActionType + | progressMouseUpChangeValValActionType; export const useVideoFlow = () => { const reducer = (state: VideoStateType, action: mergeAction) => { switch (action.type) { case 'isControl': return { ...state, isControl: action.data }; - case 'currentTime': - return { ...state, currentTime: action.data }; - case 'isPlay': - return { ...state, isPlay: action.data }; case 'progressSliderChangeVal': return { ...state, progressSliderChangeVal: action.data }; + case 'progressMouseUpChangeVal': + return { ...state, progressMouseUpChangeVal: action.data }; default: return state; } diff --git a/src/core/controls/multiple.tsx b/src/core/controls/multiple.tsx index 095dda3..080eded 100644 --- a/src/core/controls/multiple.tsx +++ b/src/core/controls/multiple.tsx @@ -1,7 +1,8 @@ -import React, { memo, FC, useState } from 'react'; +import React, { memo, FC, useState, useContext } from 'react'; import { multipleList } from '@/core/config'; +import { defaultTheme } from '@/core/config'; +import { FlowContext } from '@/core/context'; import './index.scss'; - export interface MultipleType { multipleText: string; selectPlayRate: Function; @@ -13,6 +14,10 @@ const Multiple: FC = memo(function Multiple({ selectPlayRate, multiple, }) { + const reviceProps = useContext(FlowContext); + + const { theme } = reviceProps.propsAttributes!; + const [isShow, setIsShow] = useState(false); return ( @@ -31,7 +36,7 @@ const Multiple: FC = memo(function Multiple({
  • [selectPlayRate(item.id), setIsShow(false)]} key={index} - style={{ color: multiple === item.id ? 'red' : '#fff' }} + style={{ color: multiple === item.id ? (theme ? theme : defaultTheme) : '#fff' }} > {item.name}
  • diff --git a/src/core/controls/volume.tsx b/src/core/controls/volume.tsx index 1536b87..fe345e7 100644 --- a/src/core/controls/volume.tsx +++ b/src/core/controls/volume.tsx @@ -1,5 +1,7 @@ -import React, { useImperativeHandle, useRef, forwardRef, useState } from 'react'; +import React, { useImperativeHandle, useRef, forwardRef, useState, useContext } from 'react'; import Broadcast from '@/components/svgIcon'; +import { defaultTheme } from '@/core/config'; +import { FlowContext } from '@/core/context'; import './index.scss'; export interface VolumeType { @@ -15,6 +17,10 @@ const Volume = function Volume( ) { const volumeSliderMirror = useRef(null); + const reviceProps = useContext(FlowContext); + + const { theme } = reviceProps.propsAttributes!; + const [isShow, setIsShow] = useState(false); useImperativeHandle(ref, () => ({ @@ -49,10 +55,13 @@ const Volume = function Volume( className="volume-slider-op" style={{ height: `${volume}%`, - backgroundColor: `red`, + backgroundColor: `${theme ? theme : defaultTheme}`, }} > -
    +
    diff --git a/src/core/index.scss b/src/core/index.scss index 45d0989..696b973 100644 --- a/src/core/index.scss +++ b/src/core/index.scss @@ -3,8 +3,8 @@ -khtml-user-select: none; -webkit-user-select: none; user-select: none; - width: 740px; - height: 420px; + // width: 740px; + // height: 420px; margin: 0; box-sizing: border-box; position: relative; diff --git a/src/core/index.tsx b/src/core/index.tsx index 6bb8176..4dbfec7 100644 --- a/src/core/index.tsx +++ b/src/core/index.tsx @@ -13,28 +13,24 @@ import useMandatoryUpdate from '@/utils/useMandatoryUpdate'; import Broadcast from '@/components/svgIcon'; import { useVideo } from '@/core/useVideo'; import useVideoCallback from '@/core/useVideoCallback'; +import { defaultTheme } from '@/core/config'; // import videoUrl from '@/assets/haiwang.mp4'; import '@/assets/css/reset.scss'; import './index.scss'; -const JoLPlayer = function JoLPlayer( - { - videoSrc = 'https://gs-files.oss-cn-hongkong.aliyuncs.com/okr/test/file/2021/07/01/haiwang.mp4', - onProgressSlide, +const JoLPlayer = function JoLPlayer(props: videoparameter, ref: React.Ref | undefined) { + const { + option, + onProgressMouseDown, onPlay, onPause, onTimeChange, onEndEd, - }: { - videoSrc?: string; - onPause?: Function; - onPlay?: Function; - onTimeChange?: Function; - onEndEd?: Function; - onProgressSlide?: Function; - }, - ref: React.Ref | undefined, -) { + onProgressMouseUp, + onError, + onvolumechange, + } = props; + const { videoSrc, width, height, theme } = option; /** * @description 关灯对象 */ @@ -76,20 +72,22 @@ const JoLPlayer = function JoLPlayer( video: videoRef.current, })); - const { isPlay, handleChangePlayState, currentTime, duration, isPictureinpicture, isEndEd } = - useVideo( - { - videoElement: videoRef.current, - }, - [videoRef.current], - ); + const { videoAttributes } = useVideo( + { + videoElement: videoRef.current, + }, + [videoRef.current], + ); - const callBack = useVideoCallback({ isPlay, currentTime, isEndEd }, videoFlow, { - onProgressSlide, + useVideoCallback(videoAttributes, videoFlow, { + onProgressMouseDown, + onProgressMouseUp, onPlay, onPause, onTimeChange, onEndEd, + onError, + onvolumechange, }); useEffect(() => { @@ -101,6 +99,8 @@ const JoLPlayer = function JoLPlayer( * @description 设置用户给的视频播放器长宽 */ const videoContainerElem = videoContainerRef.current; + videoContainerElem.style.width = `${width}px`; + videoContainerElem.style.height = `${height}px`; const videoElem = videoRef.current; // 设置定时器检测 3 秒后视频是否可用 timerToCheckVideoUseful.current = setTimeout(() => { @@ -120,7 +120,7 @@ const JoLPlayer = function JoLPlayer( videoElem.removeEventListener('waiting', waitingListener); videoElem.removeEventListener('playing', playingListener); }; - }, [videoRef.current]); + }, [videoRef.current, option]); const returnVideoSource = useMemo(() => { return ( @@ -132,32 +132,6 @@ const JoLPlayer = function JoLPlayer( ); }, [videoSrc]); - // useEffect(() => { - // if (videoFlow.progressSliderChangeVal) { - // onProgressSlide && onProgressSlide(videoFlow.progressSliderChangeVal); - // } - // }, [videoFlow.progressSliderChangeVal]); - - // useEffect(() => { - // if (isPlay) { - // onPlay && onPlay(isPlay); - // } else { - // onPause && onPause(isPlay); - // } - // }, [isPlay]); - - // useEffect(() => { - // if (currentTime) { - // onTimeChange && onTimeChange(currentTime); - // } - // }, [currentTime]); - - // useEffect(() => { - // if (isEndEd) { - // onEndEd && onEndEd(isEndEd); - // } - // }, [isEndEd]); - const contextProps = useMemo(() => { return Object.assign( {}, @@ -167,9 +141,10 @@ const JoLPlayer = function JoLPlayer( lightOffMaskRef: lightOffMaskRef.current, dispatch, videoFlow, + propsAttributes: option, }, ); - }, [videoRef.current, videoFlow]); + }, [videoRef.current, videoFlow, option]); return (
    @@ -179,7 +154,12 @@ const JoLPlayer = function JoLPlayer( {!isVideoUseful &&

    抱歉!视频找不到了 (。 ́︿ ̀。)

    } {isBufferring && ( - + )} @@ -188,5 +168,6 @@ const JoLPlayer = function JoLPlayer( ); }; -const JoLPlayerComponent = forwardRef(JoLPlayer); +const JoLPlayerComponent = forwardRef(JoLPlayer); + export default JoLPlayerComponent; diff --git a/src/core/progress/index.tsx b/src/core/progress/index.tsx index 65c5297..fc6c181 100644 --- a/src/core/progress/index.tsx +++ b/src/core/progress/index.tsx @@ -5,6 +5,7 @@ import { percentToMinutesAndSeconds, percentToSeconds } from '@/utils'; import useWindowClient from '@/utils/useWindowClient'; import { useProgress } from './variable'; import { hoverShowStyleType } from '@/interface'; +import { defaultTheme } from '@/core/config'; import './index.scss'; const Index = memo(function Index(props) { @@ -29,6 +30,8 @@ const Index = memo(function Index(props) { const reviceProps = useContext(FlowContext); + const { theme } = reviceProps.propsAttributes!; + const { currentTime, duration, bufferedTime } = useVideo({ videoElement: reviceProps.videoRef }, [ reviceProps.videoRef, ]); @@ -138,6 +141,7 @@ const Index = memo(function Index(props) { */ const clearIntervalFunc = () => { whenMouseUpDo(); + reviceProps.dispatch!({ type: 'progressMouseUpChangeVal', data: Date.now() }); }; /** * @description 移动悬浮层 @@ -176,12 +180,12 @@ const Index = memo(function Index(props) { className="progress-played" style={{ width: `${calculateProcessPercent}%`, - background: `red`, + background: `${theme ? theme : defaultTheme}`, }} > @@ -200,13 +204,13 @@ const Index = memo(function Index(props) {
    diff --git a/src/core/useVideo.ts b/src/core/useVideo.ts index b241c00..4b0ef4b 100644 --- a/src/core/useVideo.ts +++ b/src/core/useVideo.ts @@ -1,12 +1,18 @@ import { useRef, useMemo, useEffect, DependencyList } from 'react'; import useMandatoryUpdate from '@/utils/useMandatoryUpdate'; +import { videoAttributes } from '@/interface'; + +export interface useVideoType extends videoAttributes { + handleChangePlayState: () => void; + videoAttributes: videoAttributes; +} export const useVideo = (props: any, dep: DependencyList = []) => { const { videoElement } = props; const forceUpdate = useMandatoryUpdate(); - const videoParameter = useRef({ + const videoParameter = useRef({ isPlay: false, currentTime: 0, duration: 0, @@ -15,6 +21,7 @@ export const useVideo = (props: any, dep: DependencyList = []) => { volume: 0, multiple: 1.0, isEndEd: false, + error: null, }); const videoRef = useRef(null!); @@ -24,10 +31,6 @@ export const useVideo = (props: any, dep: DependencyList = []) => { videoRef.current = videoElement; useEffect(() => { - /** - * @description 防止在外部组件用,不更新的问题,所以要强制更新 - */ - // forceUpdate(); if (videoRef.current) { /** * @description 监听总时长 @@ -73,13 +76,14 @@ export const useVideo = (props: any, dep: DependencyList = []) => { videoRef.current.addEventListener('play', playChange); videoRef.current.addEventListener('timeupdate', timeupdate); videoRef.current.addEventListener('ended', endedChange); + videoRef.current.addEventListener('error', errorChange); } return () => { interval.current && clearInterval(interval.current); }; }, dep); - const torture = (val: any) => { + const torture = >(val: T) => { videoParameter.current = { ...videoParameter.current, ...val }; }; const pauseChange = () => { @@ -94,6 +98,9 @@ export const useVideo = (props: any, dep: DependencyList = []) => { const endedChange = () => { torture({ isEndEd: videoRef.current.ended ? true : false }); }; + const errorChange = () => { + torture({ error: Date.now() }); + }; const handleChangePlayState = () => { if (videoParameter.current.isPlay) { videoRef.current.pause(); @@ -102,10 +109,11 @@ export const useVideo = (props: any, dep: DependencyList = []) => { } }; - return useMemo( + return useMemo( () => ({ handleChangePlayState, ...videoParameter.current, + videoAttributes: videoParameter.current, }), [videoParameter.current], ); diff --git a/src/core/useVideoCallback.ts b/src/core/useVideoCallback.ts index cb0bf4a..2bf695d 100644 --- a/src/core/useVideoCallback.ts +++ b/src/core/useVideoCallback.ts @@ -1,35 +1,68 @@ import { useEffect } from 'react'; +import { videoAttributes, videoCallback } from '@/interface'; +import { VideoStateType } from './context'; -const useVideoCallback = (videoPr: any, videoFlow: any, handle: any) => { - const { isPlay, currentTime, isEndEd } = videoPr; - const { progressSliderChangeVal } = videoFlow; - const { onProgressSlide, onPlay, onPause, onTimeChange, onEndEd } = handle; +const useVideoCallback = ( + videoPr: videoAttributes, + videoFlow: VideoStateType, + handle: Partial, +) => { + const { isPlay, currentTime, isEndEd, error, volume } = videoPr; + const { progressSliderChangeVal, progressMouseUpChangeVal } = videoFlow; + const { + onProgressMouseDown, + onPlay, + onPause, + onTimeChange, + onEndEd, + onProgressMouseUp, + onError, + onvolumechange, + } = handle; useEffect(() => { if (videoFlow.progressSliderChangeVal) { - onProgressSlide && onProgressSlide(progressSliderChangeVal); + onProgressMouseDown && onProgressMouseDown(videoPr); } }, [progressSliderChangeVal]); + useEffect(() => { + if (videoFlow.progressMouseUpChangeVal) { + onProgressMouseUp && onProgressMouseUp(videoPr); + } + }, [progressMouseUpChangeVal]); + useEffect(() => { if (isPlay) { - onPlay && onPlay(isPlay); + onPlay && onPlay(videoPr); } else { - onPause && onPause(isPlay); + onPause && onPause(videoPr); } }, [isPlay]); useEffect(() => { if (currentTime) { - onTimeChange && onTimeChange(currentTime); + onTimeChange && onTimeChange(videoPr); } }, [currentTime]); useEffect(() => { if (isEndEd) { - onEndEd && onEndEd(isEndEd); + onEndEd && onEndEd(videoPr); } }, [isEndEd]); + + useEffect(() => { + if (error) { + onError && onError(); + } + }, [error]); + + useEffect(() => { + if (volume) { + onvolumechange && onvolumechange(videoPr); + } + }, [volume]); }; export default useVideoCallback; diff --git a/src/interface/index.ts b/src/interface/index.ts index 856df68..935a8d8 100644 --- a/src/interface/index.ts +++ b/src/interface/index.ts @@ -24,7 +24,80 @@ export interface videoOption { */ videoSrc: string; } -export interface videoparameter { +export interface videoAttributes { + /** + * @description 是否播放 + */ + isPlay: K; + /** + * @description 当前时间/s + */ + currentTime: T; + /** + * @description 总时长 + */ + duration: T; + /** + * @description 缓存时长/s + */ + bufferedTime: T; + /** + * @description 是否开启画中画 + */ + isPictureinpicture: K; + /** + * @description 音量 + */ + volume: T; + /** + * @description 视频播放倍数 + */ + multiple: T; + /** + * @description 是否结束 + */ + isEndEd: K; + /** + * @description 错误 + */ + error: null | T; +} +export type callBackType = (e: videoAttributes) => void; +export interface videoCallback { + /** + * @description 滑动条按下不放,拖动回调 + */ + onProgressMouseDown: T; + /** + * @description 视频开始播放回调 + */ + onPlay: T; + /** + * @description 视频暂停播放的回调 + */ + onPause: T; + /** + * @description 视频在播放,时间变化回调 + */ + onTimeChange: T; + /** + * @description 视频结束时回调 + */ + onEndEd: T; + /** + * @description 滑动条按下松开回调 + */ + onProgressMouseUp: T; + /** + * @description 视频播放失败的回调 + */ + onError: () => void; + /** + * @description 音量改变时的回调 + */ + onvolumechange: T; +} +export interface videoparameter extends Partial { style?: React.CSSProperties; /** * @description 组件的配置项