仅在可见时响应自动播放<video />(mp4)

问题描述 投票:0回答:3

我正在编写一个组件,从 Giphy 中提取 gif 并将它们呈现在 React 无限滚动组件中。无限滚动按预期工作,但后来遇到了问题。我希望 GIF 自动播放,所以我添加了自动播放属性。然后我意识到,如果同时播放所有 gif,性能就会消失。
我尝试了许多不同的解决方案,包括为每个视频组件附加一个引用,并使用react-visibility-sensor在可见时尝试播放,但我一直无法找到一种可行的方法。
这是当前每个 mp4 自动播放的组件。我已经删除了 VisibilitySensor,因为我无法让它工作。

  const videoRefs = useRef(
    [...new Array(gifArray.length)].map(() => createRef()),
  );

  return (
    <div>
      {gifArray && (
        <InfiniteScroll
          dataLength={gifArray}
          next={getMore}
          hasMore={true}
          loader={<div>Loading...</div>}
        >
          {gifArray.map((gif, i) => {
            return (
              <video
                width='320'
                height='240'
                loop
                autoPlay
                key={gif.id}
                ref={videoRefs.current[i]}
              >
                <source src={gif.images.downsized_small.mp4} type='video/mp4' />
              </video>
            );
          })}
        </InfiniteScroll>
      )}
    </div>
  );
};

数据在单独的组件中检索并作为道具传递。

export const HomePage = () => {
  const [gifObject, setGifObject] = useState([]);
  const [searchValue, setSearchValue] = useState('');
  const [pageNumber, setPageNumber] = useState(0);

  const handleSearch = (value) => {
    setSearchValue(value);
    fetch(
      `http://api.giphy.com/v1/gifs/search?q=${value}&api_key=${API_KEY}&limit=20`,
    )
      .then((data) => data.json())
      .then((result) => {
        setGifObject(result);
      });
  };
  return (
    <div>
      <SearchForm handleSearchValue={handleSearch} />
      {gifObject?.data?.length > 1 ? (
        <GifDisplay gifArray={gifObject.data} getMore={getData} />
      ) : null}
    </div>
  );
}
javascript html reactjs html5-video giphy
3个回答
6
投票

我最终解决了这个问题。 我为每个 gif 创建了一个组件,并使用一个名为

react-visibility-sensor
的包来检查它是否可见。
GifDisplay
组件仍然非常接近相同:

// GifDisplay.tsx
export const GifDisplay = ({ gifArray, getMore, handleSearch }) => {
  return (
    <GifDisplayWrapper>
      {gifArray && (
        <InfiniteScroll
          dataLength={gifArray}
          next={getMore}
          hasMore={true}
          loader={<div>Loading...</div>}
        >
          <ArrayWrapper>
            {gifArray.map((gif) => {
              return (
                <div key={gif.id}>
                  <SingleGif gif={gif} />
                </div>
              );
            })}
          </ArrayWrapper>
        </InfiniteScroll>
      )}
    </GifDisplayWrapper>
  );
};

SingleGif
组件使用了
react-visibility-sensor
并更新了每个组件的状态。

// SingleGif.tsx
import VisibilitySensor from 'react-visibility-sensor';

export const SingleGif = ({ gif }) => {
  const videoRef = useRef(null);
  const [isVisible, setIsVisible] = useState(false);

  useEffect(() => {
    if (isVisible) {
      videoRef.current.play();
    } else {
      if (videoRef.current.play) {
        videoRef.current.pause();
      }
    }
  }, [isVisible]);

  return (
    <VisibilitySensor onChange={(isVisible) => setIsVisible(isVisible)}>
      <video width='320' height='240' loop ref={videoRef}>
        <source src={gif.images.downsized_small.mp4} type='video/mp4' />
      </video>
    </VisibilitySensor>
  );
};

0
投票

使用

react-intersection-observer
而不是
react-visibility-sensor
,如上面有人评论的那样。
react-visibility-sensor
不再可用。


0
投票

使用

react-intersection-observer
,您只需对
SingleGif
组件进行小调整。

const videoRef = useRef<HTMLVideoElement>(null);
const { ref, inView, entry } = useInView({
  /* Optional options */
  threshold: 0,
});

return(
  <div ref={ref}>
    <video
      ref={videoRef}
      ...
    />
  </div>
);
© www.soinside.com 2019 - 2024. All rights reserved.