问题
I want to dynamically change the width of my vimeo player adapting to the window width. You can see the full code of the component at the end of the question and maybe there is already a way simpler approach to dynamically change the width of the player so I don't have to deal with the issues at all (The responsive option provided by vimeo does not work for me).
The issue I am having with my current solution: I don't want to trigger a change if the player goes into fullscreen or rotates the phone on fullscreen since vimeo already handles those changes automatically but I have a hard time to detect if the player is in fullscreen.
const isFullscreen = (document.fullscreenElement
|| document.webkitFullscreenElement
|| document.mozFullScreenElement
|| document.msFullscreenElement
|| playerWidth === delayedWidth)
This solution breaks for iphone 11 pro and probably all Safari browsers since fullScreen is not fully implemented there.
import React, {
useEffect, useContext, useState, useRef,
} from 'react';
import PropTypes from 'prop-types';
import Player from '@vimeo/player';
import STYLES from '../../enums/styles';
import { BrowserContext } from '../../contexts/BrowserContext';
const TAG = 'player';
/**
* remove event listeners
* @param {object} playerRef
*/
function removeEventListeners(playerRef) {
if (!playerRef.current) return;
playerRef.current.off('ended');
playerRef.current.off('pause');
playerRef.current.off('play');
}
/**
* remove interval
* @param {object} intervalRef
*/
function removeInterval(intervalRef) {
if (!intervalRef.current) return;
window.clearInterval(intervalRef.current);
}
/**
* 640×480, 800×600, 960×720, 1024×768, 1280×960,
* 1400×1050, 1440×1080 , 1600×1200, 1856×1392, 1920×1440, and 2048×1536
* @param {} width
*/
function computeRatio(delayedWidth) {
const height = window.innerHeight;
const width = delayedWidth - delayedWidth * 0.1;
if (height <= 480) {
return width > 640 ? 640 : width;
}
if (height <= 600) {
return width > 800 ? 800 : width;
}
if (height <= 720) {
return width > 960 ? 960 : width;
}
if (height <= 768) {
return width > 1024 ? 1024 : width;
}
if (height <= 960) {
return width > 1280 ? 1280 : width;
}
if (height <= 1050) {
return width > 1400 ? 1400 : width;
}
if (height <= 1080) {
return width > 1440 ? 1440 : width;
}
if (height <= 1200) {
return width > 1600 ? 1600 : width;
}
if (height <= 1392) {
return width > 1856 ? 1856 : width;
}
if (height <= 1440) {
return width > 1920 ? 1920 : width;
}
if (height <= 1536) {
return width > 2048 ? 2048 : width;
}
return width;
}
const VideoPlayer = ({
index, title, description, link, onProgress, latestProgress,
}) => {
const { delayedWidth } = useContext(BrowserContext);
const [time, setTime] = useState(latestProgress < 1 ? latestProgress : 0);
const playerRef = useRef(null);
const intervalRef = useRef(null);
useEffect(() => {
console.tag(TAG).debug('changing delayed width', delayedWidth);
const asyncEffect = async () => {
const player = playerRef.current;
if (player) {
const playerWidth = await player.getVideoWidth();
const isFullscreen = document.fullscreenElement
|| document.webkitFullscreenElement
|| document.mozFullScreenElement
|| document.msFullscreenElement
|| playerWidth === delayedWidth;
console.tag(TAG).debug('fullscreen detected', isFullscreen);
const isMobile = window.innerWidth <= STYLES.breakpoints.phoneWidth;
const isLandscape = window.innerWidth > window.innerHeight;
if (isFullscreen || (isLandscape && isMobile)) {
console.tag(TAG).debug('isLandscape, isMobile', isLandscape, isMobile);
return;
}
removeEventListeners(playerRef);
playerRef.current = null;
player.pause();
player.destroy();
}
if (intervalRef.current) {
removeInterval(intervalRef);
intervalRef.current = null;
}
const options = { id: link, width: computeRatio(delayedWidth) };
const newPlayer = new Player(`frame-${title}-${index}`, options);
playerRef.current = newPlayer;
if (time) {
newPlayer.getDuration().then((duration) => {
const seconds = duration * time;
newPlayer.setCurrentTime(seconds);
});
}
const keepTrackProgress = async () => {
// gets duration of video in seconds
const duration = await newPlayer.getDuration();
intervalRef.current = window.setInterval(() => {
newPlayer.getCurrentTime().then((seconds) => {
// `seconds` indicates the current playback position of the video
const progress = seconds / duration;
console.tag(TAG).debug(`progress: ${progress}, duration ${duration}, seconds ${seconds}`);
onProgress(progress);
setTime(progress);
});
// track every next 10 seconds of progress
}, 10000);
};
newPlayer.on('ended', () => {
removeInterval(intervalRef);
intervalRef.current = null;
onProgress(1);
setTime(1);
});
newPlayer.on('pause', ({ duration, seconds }) => {
removeInterval(intervalRef);
intervalRef.current = null;
const progress = seconds / duration;
console.tag(TAG).debug(`progress at paused: ${progress}, duration ${duration}, seconds ${seconds}`);
onProgress(progress);
setTime(progress);
});
newPlayer.on('play', () => {
keepTrackProgress();
});
};
asyncEffect();
return () => {
removeInterval(intervalRef);
removeEventListeners(playerRef);
};
}, [delayedWidth]);
return (
<div className="video-player">
<div id={`frame-${title}-${index}`} className="frame-wrapper" />
<div className="details">
<h1>{title}</h1>
<p>{description}</p>
</div>
</div>
);
};
VideoPlayer.propTypes = {
index: PropTypes.number.isRequired,
title: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
link: PropTypes.string.isRequired,
onProgress: PropTypes.func.isRequired,
latestProgress: PropTypes.number.isRequired,
};
export default VideoPlayer;
回答1:
I'm using u-wave vimeo player, where the responsive has been taken care.
import Vimeo from '@u-wave/react-vimeo';`
<Vimeo
video={videoURL}
autoplay={false}
controls={true}
responsive={true}
onEnd={() => { onVideoEnd() }}
style={{ justifyContent: 'center'}}
start={0}
onTimeUpdate={(duration) => { console.log(duration }} />
来源:https://stackoverflow.com/questions/60921169/vimeo-detect-fullscreen-to-block-fetching-of-new-player-dynamic-width-changes