首页 > 解决方案 > Vimeo,检测全屏以阻止获取新播放器(动态宽度更改)

问题描述

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

我当前的解决方案遇到的问题:如果播放器进入全屏模式或全屏旋转手机,我不想触发更改,因为 vimeo 已经自动处理这些更改,但我很难检测播放器是否是全屏。

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

这个解决方案对 iphone 11 pro 和可能所有的 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;

标签: javascripthtmlreactjsbrowservimeo-player

解决方案


我正在使用 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 }} />

推荐阅读