admin管理员组

文章数量:1125362

I created a video listing similar to TikTok and YouTube shorts using the 'react-window-infinite-loader', 'react-window', 'react-virtualized-auto-sizer', and 'video.js'. When I set the item snap, it works fine on the Chrome browser but not properly with the Safari browser. After 2 items, when I snap the third item, it automatically bounces back to 2 items.

Here are the code sandbox example links
=%2Fsrc%2FApp.js%3A1%2C1-114%2C1
/

 import React, { useRef, useState, memo } from "react";
import { FixedSizeList, areEqual } from "react-window";
import InfiniteLoader from "react-window-infinite-loader";
import AutoSizer from "react-virtualized-auto-sizer";
import VideoJS from "./video";
import "./styles.css";

// Row component
const Row = memo(({ index, style, data }) => {
  const { videoList, isItemLoaded, handlePlayerReady } = data;

  // Render loading state
  if (!isItemLoaded(index)) {
    return (
      <div
        style={{
          ...style,
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
        }}
      >
        Loading...
      </div>
    );
  }

  const video = videoList[index];

  const videoJsOptions = {
    autoplay: true,
    controls: true,
    muted: true,
    playsinline: true,
    sources: [{ src: video.src, type: video.type }],
  };

  return (
    <div
      style={{
        ...style,
        scrollSnapAlign: "start",
        scrollBehavior: "smooth",
      }}
    >
      <VideoJS options={videoJsOptions} onReady={handlePlayerReady} />
    </div>
  );
}, areEqual);

export default function App() {
  const [videoList, setVideoList] = useState(
    Array(20)
      .fill()
      .map((_, index) => ({
        id: index,
        src: ".m3u8",
        type: "application/x-mpegurl",
      }))
  );

  const playerRef = useRef(null);

  const handlePlayerReady = (player) => {
    playerRef.current = player;
    player.on("waiting", () => console.log("player is waiting"));
    player.on("dispose", () => console.log("player will dispose"));
  };

  const loadMoreItems = async () => {
    const newVideos = Array(10)
      .fill()
      .map((_, index) => ({
        id: videoList.length + index,
        src: ".m3u8",
        type: "application/x-mpegurl",
      }));

    setTimeout(() => setVideoList((prev) => [...prev, ...newVideos]), 1000);
  };

  const isItemLoaded = (index) => index < videoList.length;

  return (
    <div style={{ height: "100vh", overflow: "hidden" }}>
      <InfiniteLoader
        isItemLoaded={isItemLoaded}
        loadMoreItems={loadMoreItems}
        itemCount={videoList.length + 1}
      >
        {({ onItemsRendered, ref }) => (
          <AutoSizer>
            {({ width, height }) => (
              <FixedSizeList
                height={height}
                width={width}
                itemCount={videoList.length}
                itemSize={550}
                onItemsRendered={onItemsRendered}
                ref={ref}
                itemData={{ videoList, isItemLoaded, handlePlayerReady }}
                style={{
                  scrollSnapType: "y mandatory",
                  WebkitScrollSnapType: "y mandatory",
                  overflow: "auto",
                }}
              >
                {Row}
              </FixedSizeList>
            )}
          </AutoSizer>
        )}
      </InfiniteLoader>
    </div>
  );
}
import React from "react";
import videojs from "video.js";
import "video.js/dist/video-js.css";
import de from "video.js/dist/lang/de.json";

export const VideoJS = (props) => {
  videojs.addLanguage("de", de);
  const videoRef = React.useRef(null);
  const playerRef = React.useRef(null);
  const { options, onReady } = props;

  React.useEffect(() => {
    // make sure Video.js player is only initialized once
    if (!playerRef.current) {
      const videoElement = videoRef.current;
      if (!videoElement) return;

      const player = (playerRef.current = videojs(videoElement, options, () => {
        console.log("player is ready");
        onReady && onReady(player);
      }));
    } else {
      // you can update player here [update player through props]
    }
  }, [options, onReady]);


  return (
    <div
      data-vjs-player
      style={{
        paddingX: "15px",
        // backgroundColor: "white",
      }}
    >
      <video
        ref={videoRef}
        className="video-js vjs-big-play-centered"
        width={"250px"}
        height={"450px"}
      />
    </div>
  );
};

export default VideoJS;

本文标签: Safari snap issue with scrollSnapType quoty mandatoryquot using reactwindowStack Overflow