diff --git a/packages/griffith/src/components/Player.tsx b/packages/griffith/src/components/Player.tsx index da50b6e5..cbeac472 100644 --- a/packages/griffith/src/components/Player.tsx +++ b/packages/griffith/src/components/Player.tsx @@ -370,22 +370,21 @@ class InnerPlayer extends Component { handleVideoError = () => { this.setState({ isPlaying: false, - isLoading: false, }) } - handleVideoDurationChange = (duration: any) => { + handleVideoDurationChange = (duration: number) => { this.setState({duration}) } - handleVideoTimeUpdate = (currentTime: any) => { + handleVideoTimeUpdate = (currentTime: number) => { const {isLoading} = this.state if (isLoading || this.isSeeking) return if (this.isSeeking) return this.setState({currentTime}) } - handleVideoVolumeChange = (volume: any) => { + handleVideoVolumeChange = (volume: number) => { volume = Math.round(volume * 100) / 100 this.setState({volume}) storage.set('@griffith/history-volume', volume) @@ -407,19 +406,8 @@ class InnerPlayer extends Component { } } - handleVideoWaiting = () => { - if (this.showLoaderTimeout !== null) return - this.showLoaderTimeout = setTimeout(() => { - this.setState({isLoading: true}) - }, 1000) - } - - handleVideoPlaying = () => { - if (this.showLoaderTimeout !== null) { - clearTimeout(this.showLoaderTimeout) - this.showLoaderTimeout = null - } - this.setState({isLoading: false}) + handleLoadingChange = (isLoading: boolean) => { + this.setState({isLoading}) } handleVideoSeeking = () => { @@ -621,8 +609,7 @@ class InnerPlayer extends Component { onError={this.handleVideoError} onDurationChange={this.handleVideoDurationChange} onTimeUpdate={this.handleVideoTimeUpdate} - onWaiting={this.handleVideoWaiting} - onPlaying={this.handleVideoPlaying} + onLoadingChange={this.handleLoadingChange} onSeeking={this.handleVideoSeeking} onSeeked={this.handleVideoSeeked} onProgress={this.handleVideoProgress} diff --git a/packages/griffith/src/components/Video.tsx b/packages/griffith/src/components/Video.tsx index 4b1837c7..d1ac3d04 100644 --- a/packages/griffith/src/components/Video.tsx +++ b/packages/griffith/src/components/Video.tsx @@ -32,14 +32,13 @@ type VideoProps = { volume: number currentQuality?: Quality sources?: PlaySource[] + onLoadingChange?: (isLoading: boolean) => void onPlay?: (...args: any[]) => any onPause?: (...args: any[]) => any onEnded?: (...args: any[]) => any onLoadedData?: (...args: any[]) => any onDurationChange?: (...args: any[]) => any onTimeUpdate?: (...args: any[]) => any - onWaiting: (...args: any[]) => any - onPlaying: (...args: any[]) => any onSeeking?: (...args: any[]) => any onSeeked?: (...args: any[]) => any onProgress?: (values: ProgressValue[]) => any @@ -235,7 +234,7 @@ class Video extends Component { this.setRate(this.props.currentPlaybackRate) this.props.onEvent( EVENTS.CHANGE_QUALITY_SUCCESS, - (this.props as any).currentQuality + this.props.currentQuality ) } } @@ -247,23 +246,29 @@ class Video extends Component { } } - handleLoadedData = () => { - const {onLoadedData} = this.props - onLoadedData && onLoadedData() - } - - handleWaiting = () => { - if (!this.loading) { - this.loading = true - } - this.props.onWaiting() - } - - handlePlaying = () => { - if (this.loading) { - this.loading = false + prevLoadingEvent?: 'waiting' | 'canplay' | 'playing' | 'error' = undefined + handleNativeEvent = (e: React.SyntheticEvent) => { + const type = e.type + if ( + type === 'waiting' || + type === 'canplay' || + type === 'playing' || + type === 'error' + ) { + if (type === 'waiting') { + this.loading = true + this.props.onLoadingChange?.(this.loading) + } else if ( + // 修复 Safari 中可能不触发 playing 问题:https://github.com/zhihu/griffith/issues/234 + (type === 'canplay' && this.prevLoadingEvent === 'waiting') || + type === 'playing' || + type === 'error' + ) { + this.loading = false + this.props.onLoadingChange?.(this.loading) + } + this.prevLoadingEvent = type } - this.props.onPlaying() } handleTimeUpdate = (arg: any) => { @@ -375,8 +380,7 @@ class Video extends Component { onDurationChange={this.handleDurationChange} onTimeUpdate={this.handleTimeUpdate} onProgress={this.handleProgress} - onWaiting={this.handleWaiting} - onPlaying={this.handlePlaying} + onNativeEvent={this.handleNativeEvent} paused={paused} sources={sources} currentQuality={currentQuality} diff --git a/packages/griffith/src/components/VideoWithMessage.tsx b/packages/griffith/src/components/VideoWithMessage.tsx index b0b381d6..5259bc18 100644 --- a/packages/griffith/src/components/VideoWithMessage.tsx +++ b/packages/griffith/src/components/VideoWithMessage.tsx @@ -38,6 +38,7 @@ function getMediaEventPayload(event: VideoEvent) { export type VideoComponentType = React.ComponentType type VideoWithMessageProps = NativeVideoProps & { + onNativeEvent?: (event: VideoEvent) => void Video: VideoComponentType } @@ -56,11 +57,12 @@ const VideoWithMessage = React.forwardRef< }, [props]) const newProps = useMemo(() => { - const newProps: Partial = {} + const newProps: Partial = {} eventMap.forEach(([eventName, key]) => { newProps[key] = (event: VideoEvent, ...args: any[]) => { emitEvent(eventName, getMediaEventPayload(event)) const handler = propsRef.current[key] as AnyFunction + propsRef.current.onNativeEvent?.(event) return handler?.(event, ...args) } }) @@ -80,7 +82,12 @@ const VideoWithMessage = React.forwardRef< [updateVideoSize] ) - const {Video, ...otherProps} = props + const { + Video, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + onNativeEvent, + ...otherProps + } = props return (