Browse Source

feat: 播放器

ZW\zwf97 6 months ago
parent
commit
d71c293f15
2 changed files with 121 additions and 4 deletions
  1. 117 0
      src/pages/Play/components/Player.tsx
  2. 4 4
      src/pages/Play/index.tsx

+ 117 - 0
src/pages/Play/components/Player.tsx

@@ -0,0 +1,117 @@
+
+import React, { useRef, useState, useEffect } from 'react';
+import { Button } from 'antd';
+
+interface VideoSyncPlayerProps {
+  videoUrls: string[];
+}
+
+const VideoSyncPlayer: React.FC<VideoSyncPlayerProps> = ({ videoUrls }) => {
+  const videoRefs = useRef<(HTMLVideoElement | null)[]>([]);
+  const [progress, setProgress] = useState(0);
+  const [isPlaying, setIsPlaying] = useState(false);
+  const [duration, setDuration] = useState(0);
+
+  // 同步所有视频状态
+  const syncVideos = () => {
+    const mainVideo = videoRefs.current[0];
+    if (!mainVideo) return;
+
+    const currentTime = mainVideo.currentTime;
+    setProgress((currentTime / duration) * 100);
+
+    videoRefs.current.forEach(video => {
+      if (video && video !== mainVideo) {
+        video.currentTime = currentTime;
+        if (isPlaying) {
+          video.play()
+        } else {
+          video.pause()
+        }
+      }
+    });
+  };
+
+  // 处理播放/暂停
+  const togglePlay = () => {
+    setIsPlaying(!isPlaying);
+  };
+
+  // 处理进度条拖动
+  const handleSeek = (e: React.ChangeEvent<HTMLInputElement>) => {
+    const seekTime = (Number(e.target.value) / 100) * duration;
+    videoRefs.current.forEach(video => {
+      if (video) video.currentTime = seekTime;
+    });
+  };
+
+  // 初始化视频设置
+  useEffect(() => {
+    const mainVideo = videoRefs.current[0];
+    if (!mainVideo) return;
+
+    const handleLoadedMetadata = () => {
+      setDuration(mainVideo.duration);
+      if (videoRefs.current.every(v => v!.readyState > 2)) {
+        setIsPlaying(true);
+      }
+    };
+
+    mainVideo.addEventListener('loadedmetadata', handleLoadedMetadata);
+    return () => {
+      mainVideo.removeEventListener('loadedmetadata', handleLoadedMetadata);
+    };
+  }, []);
+
+  return (
+    <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
+      {/* 主视频区域 */}
+      <div>
+        <video
+          ref={el => videoRefs.current[0] = el}
+          width="1150"
+          height="475"
+          style={{ objectFit: 'cover' }}
+          muted
+          onTimeUpdate={syncVideos}
+        >
+          <source src={videoUrls[0]} type="video/mp4" />
+        </video>
+      </div>
+
+      {/* 副视频区域 */}
+      <div style={{ display: 'flex', justifyContent: 'center', gap: 25 }}>
+        {[1, 2].map(index => (
+          <video
+            key={index}
+            ref={el => videoRefs.current[index] = el}
+            width="565"
+            height="375"
+            style={{ objectFit: 'cover' }}
+            muted
+            onTimeUpdate={syncVideos}
+          >
+            <source src={videoUrls[index]} type="video/mp4" />
+          </video>
+        ))}
+      </div>
+
+      {/* 控制区域 */}
+      <div style={{ padding: 20, display: 'flex', flexDirection: 'column' }}>
+        <Button onClick={togglePlay} style={{ marginBottom: 10 }}>
+          {isPlaying ? '暂停' : '播放'}
+        </Button>
+        <input
+          type="range"
+          min="0"
+          max="100"
+          value={progress}
+          onChange={handleSeek}
+          style={{ width: '100%' }}
+        />
+      </div>
+    </div>
+  );
+};
+
+export default VideoSyncPlayer;

+ 4 - 4
src/pages/Play/index.tsx

@@ -3,7 +3,7 @@ import {
 } from '@ant-design/pro-components';
 import React from 'react';
 import './style/index.less';
-import { Card, Segmented } from 'antd';
+import { Card } from 'antd';
 import { ArrowLeftOutlined } from '@ant-design/icons';
 import dayjs from 'dayjs';
 import './style/index.less'
@@ -38,15 +38,15 @@ const TableList: React.FC<unknown> = () => {
           <div>左侧切换播放模式</div>
           <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
             <div>
-              <video width="1150" height="475" autoPlay>
+              <video width="1150" height="475" style={{ objectFit: 'cover' }} autoPlay>
                 <source src="http://player.alicdn.com/video/aliyunmedia.mp4" type="video/ogg" />
               </video>
             </div>
             <div style={{ display: 'flex', justifyContent:'center', gap: 25 }}>
-              <video width="565" height="375" autoPlay>
+              <video width="565" height="375" style={{ objectFit: 'cover' }} autoPlay>
                 <source src="http://player.alicdn.com/video/aliyunmedia.mp4" type="video/ogg" />
               </video>
-              <video width="565" height="375" autoPlay>
+              <video width="565" height="375" style={{ objectFit: 'cover' }} autoPlay>
                 <source src="http://player.alicdn.com/video/aliyunmedia.mp4" type="video/ogg" />
               </video>
             </div>