Vimeo,检测全屏阻止获取新玩家(动态宽度变化)



我想动态更改vimeo播放器的宽度以适应窗口宽度。你可以在问题的末尾看到组件的完整代码,也许已经有一种更简单的方法可以动态更改播放器的宽度,这样我就不必处理这些问题了(vimeo提供的响应选项对我不起作用(。

我目前的解决方案存在的问题是:如果玩家进入全屏或在全屏上旋转手机,我不想触发更改,因为vimeo已经自动处理这些更改,但我很难检测到玩家是否处于全屏。

const isFullscreen = (document.fullscreenElement
|| document.webkitFullscreenElement
|| document.mozFullScreenElement
|| document.msFullscreenElement
|| playerWidth === delayedWidth)

该解决方案适用于iphone11pro,可能适用于所有Safari浏览器,因为fullScreen在那里没有完全实现。

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;

我使用的是u-wave vimeo播放器,其中的响应已经得到了处理。

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 }} />

@vimeo/player包背后的团队发布了新的全屏方法!它就像一个符咒,解决了我的问题。

如果你遇到了类似的问题,请查看更新的@vimeo/player文档:https://www.npmjs.com/package/@vimeo/player#getfullscreen承诺错误

我更新和测试的代码如下:

import React, {
useEffect, useContext, useState, useRef,
} from 'react';
import PropTypes from 'prop-types';
import Player from '@vimeo/player';
import { BrowserContext } from '../../contexts/BrowserContext';
const TAG = 'player';
/**
* remove event listeners
* @param {object} player
*/
function removeEventListeners(player) {
if (!player) return;
player.off('ended');
player.off('pause');
player.off('play');
}
/**
* remove interval
* @param {number} interval
*/
function removeInterval(interval) {
console.tag(TAG).debug('removeInterval called');
window.clearInterval(interval);
}
/**
* 640×480, 800×600, 960×720, 1024×768, 1280×960,
* 1400×1050, 1440×1080 , 1600×1200, 1856×1392, 1920×1440, and 2048×1536
* @param {number} width
*/
function computeRatio(delayedWidth, percentage = 0.9) {
const height = window.innerHeight;
const width = delayedWidth - (delayedWidth * (1 - percentage));
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, link, onProgress, latestProgress, widthPercentage, onVideoEnded,
}) => {
const { delayedWidth } = useContext(BrowserContext);
const [progress, setProgress] = 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) {
console.tag(TAG).debug('player detected, checking fullscreen');
const isFullscreen = await player.getFullscreen();
console.tag(TAG).debug('fullscreen detected', isFullscreen);
if (isFullscreen) {
return;
}
removeEventListeners(player);
playerRef.current = null;
player.pause(); // gets rid of interval
player.destroy();
}
const options = { id: link, width: computeRatio(delayedWidth, widthPercentage) };
const newPlayer = new Player(`frame-${index}`, options);
playerRef.current = newPlayer;
if (progress) {
newPlayer.getDuration().then((duration) => {
const seconds = duration * progress;
newPlayer.setCurrentTime(seconds);
});
}
const keepTrackProgress = async () => {
// gets duration of video in seconds
const duration = await newPlayer.getDuration();
intervalRef.current = window.setInterval(() => {
const currentPlayer = playerRef.current;
if (!currentPlayer) {
return;
}
currentPlayer.getCurrentTime().then((seconds) => {
// `seconds` indicates the current playback position of the video
const newProgress = seconds / duration;
console.tag(TAG).debug(`progress: ${newProgress}, duration ${duration}, seconds ${seconds}`);
onProgress(newProgress);
setProgress(newProgress);
});
// track every next 10 seconds of progress
}, 10000);
};
newPlayer.on('ended', () => {
console.tag(TAG).debug('player onEnded');
removeInterval(intervalRef.current);
intervalRef.current = null;
onProgress(1);
setProgress(1);
onVideoEnded();
});
newPlayer.on('pause', ({ duration, seconds }) => {
console.tag(TAG).debug('player onPause');
removeInterval(intervalRef.current);
intervalRef.current = null;
const newProgress = seconds / duration;
console.tag(TAG).debug(`progress at paused: ${newProgress}, duration ${duration}, seconds ${seconds}`);
onProgress(newProgress);
setProgress(newProgress);
});
newPlayer.on('play', () => {
console.tag(TAG).debug('player onPlay');
keepTrackProgress();
});
};
asyncEffect();
}, [delayedWidth]);
useEffect(() => () => {
removeInterval(intervalRef.current);
removeEventListeners(playerRef.current);
if (playerRef.current) {
playerRef.current.destroy();
}
}, []);
return (
<div id={`frame-${index}`} className="frame-wrapper" />
);
};

VideoPlayer.propTypes = {
index: PropTypes.number.isRequired,
link: PropTypes.string.isRequired,
onProgress: PropTypes.func.isRequired,
onVideoEnded: PropTypes.func,
latestProgress: PropTypes.number.isRequired,
widthPercentage: PropTypes.number,
};
VideoPlayer.defaultProps = {
widthPercentage: 0.9,
onVideoEnded: () => {},
};
export default VideoPlayer;

最新更新