React鼠标滚动控制视频分段播放功能故障求助
React滚动控制视频分段播放问题
需求
- 向下滚动时播放数秒视频后停止
- 向上滚动时播放反向制作的视频
- 自定义可点击进度条
现存问题
- 滚动时页面会滑至下一个组件,无法停留在视频组件直至所有视频片段播放完成
- 从第三个组件返回视频组件后,反向滚动功能失效
代码实现
ScrollVideo.js
import React, { useRef, useEffect, useState } from 'react'; import styled from 'styled-components'; import ScrollVid from '../content/videos/ft.mp4'; import VidImage from '../content/images/vidcover.JPG'; const VideoWrapper = styled.div` position: relative; width: 100%; height: 100vh; overflow: hidden; video { width: 100%; height: 100%; object-fit: cover; } `; const ProgressBar = styled.div` position: absolute; bottom: 0; left: 0; height: 5px; background: #fff; transition: width 0.3s ease; width: ${(props) => (props.$progress / 7) * 100}%; `; const ScrollVideo = () => { const videoRef = useRef(null); const containerRef = useRef(null); const [scrollIndex, setScrollIndex] = useState(0); const [isPlaying, setIsPlaying] = useState(false); const [isInView, setIsInView] = useState(false); useEffect(() => { const observer = new IntersectionObserver( (entries) => { const entry = entries[0]; setIsInView(entry.isIntersecting); }, { threshold: 0.8 } ); if (containerRef.current) { observer.observe(containerRef.current); } return () => { if (containerRef.current) { observer.unobserve(containerRef.current); } }; }, []); useEffect(() => { if (isInView) { const handleWheel = (event) => { event.preventDefault(); if (isPlaying) return; const { deltaY } = event; const newScrollIndex = Math.min( 8, Math.max(0, scrollIndex + (deltaY > 0 ? 1 : -1)) ); if (newScrollIndex !== scrollIndex) { setScrollIndex(newScrollIndex); } }; window.addEventListener('wheel', handleWheel, { passive: false }); return () => { window.removeEventListener('wheel', handleWheel); }; } }, [isInView, isPlaying, scrollIndex]); useEffect(() => { const video = videoRef.current; if (video && scrollIndex > 0 && scrollIndex <= 7) { setIsPlaying(true); video.currentTime = (scrollIndex - 1) * 3; video.play(); const timeout = setTimeout(() => { video.pause(); setIsPlaying(false); }, 3000); return () => clearTimeout(timeout); } else if (scrollIndex === 8) { const nextSection = containerRef.current.nextElementSibling; if (nextSection) { setScrollIndex(9); // 防止重复触发跳转 nextSection.scrollIntoView({ behavior: 'smooth' }); } } else if (scrollIndex === 0) { const prevSection = containerRef.current.previousElementSibling; if (prevSection) { prevSection.scrollIntoView({ behavior: 'smooth' }); } } }, [scrollIndex]); return ( <VideoWrapper ref={containerRef}> <video ref={videoRef} muted preload="metadata" poster={VidImage} playsInline className="w-full h-auto object-cover" > <source src={ScrollVid} type="video/mp4" /> </video> <ProgressBar $progress={scrollIndex} /> </VideoWrapper> ); }; export default ScrollVideo;
App.js
import React from 'react'; import Header from './components/Header'; import HeroSection from './components/HeroSection'; import SecondSection from './components/SecondSection'; import Specs from './components/SpecsTruck' import Scroll from './components/ScrollVideo' import Vid from './components/FullpageWithVideos' import './style.css' function App() { return ( <div style={{ backgroundColor: 'black', color: 'white' }}> <Header /> <HeroSection /> <Vid/> <Scroll/> <SecondSection /> <Specs/> </div> ); } export default App;
Style.css
.video-section { position: relative; width: 100%; height: 100vh; overflow: hidden; } .video-section video { width: 100%; height: 100%; object-fit: cover; } .progress-bar { position: absolute; bottom: 0; left: 0; height: 5px; background: #fff; transition: width 0.3s; }
内容的提问来源于stack exchange,提问作者Malik Usman
相关产品推荐
相关产品推荐

