Day11 要做的是客製化的影片播放器
const VIDEO_URL =
"https://github.com/wesbos/JavaScript30/raw/master/11%20-%20Custom%20Video%20Player/652333414.mp4";
const [isPlaying, setIsPlaying] = useState<boolean>(false);
const [volume, setVolume] = useState<number>(1);
const [isMuted, setIsMuted] = useState<boolean>(false);
const [playbackRate, setPlaybackRate] = useState<number>(1);
const [progress, setProgress] = useState<number>(0);
const videoRef = useRef<HTMLVideoElement>(null);
const progressRef = useRef<HTMLInputElement>(null);
const updateProgress = (): void => {
const video = videoRef.current;
if (video) {
const percentage = (video.currentTime / video.duration) * 100;
setProgress(percentage);
}
};
const skip = (amount: number): void => {
const video = videoRef.current;
if (video) {
video.currentTime += amount;
}
};
const handleProgressChange = (e: ChangeEvent<HTMLInputElement>): void => {
const video = videoRef.current;
if (video) {
const newTime = (parseFloat(e.target.value) / 100) * video.duration;
video.currentTime = newTime;
setProgress(parseFloat(e.target.value));
}
};
const togglePlay = (): void => {
const video = videoRef.current;
if (video) {
if (isPlaying) {
video.pause();
} else {
video.play();
}
setIsPlaying(!isPlaying);
}
};
const handleVolumeChange = (e: ChangeEvent<HTMLInputElement>): void => {
const newVolume = parseFloat(e.target.value);
setVolume(newVolume);
if (videoRef.current) {
videoRef.current.volume = newVolume;
}
setIsMuted(newVolume === 0);
};
const toggleMute = (): void => {
const video = videoRef.current;
if (video) {
if (isMuted) {
video.volume = volume;
setIsMuted(false);
} else {
video.volume = 0;
setIsMuted(true);
}
}
};
const handlePlaybackRateChange = (
e: ChangeEvent<HTMLSelectElement>
): void => {
const newRate = parseFloat(e.target.value);
setPlaybackRate(newRate);
if (videoRef.current) {
videoRef.current.playbackRate = newRate;
}
};
先顯示影片元素
控制項則是利用絕對定位印在影片上
<div className="max-w-4xl mx-auto p-4 bg-gray-900 rounded-lg shadow-lg">
<div className="relative overflow-hidden rounded-lg">
<video
ref={videoRef}
className="w-full cursor-pointer"
onClick={togglePlay}
onTimeUpdate={updateProgress}
src={VIDEO_URL}
>
Your browser does not support the video tag.
</video>
<div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black to-transparent p-4">
<div className="flex items-center justify-between mb-2">
<button
onClick={togglePlay}
className="text-white hover:text-blue-400 transition-colors duration-200"
>
{isPlaying ? (
<PauseIcon className="w-8 h-8" />
) : (
<PlayArrowIcon className="w-8 h-8" />
)}
</button>
<div className="flex items-center space-x-4">
<button
onClick={toggleMute}
className="text-white hover:text-blue-400 transition-colors duration-200"
>
{isMuted ? (
<VolumeOffIcon className="w-6 h-6" />
) : (
<VolumeUpIcon className="w-6 h-6" />
)}
</button>
<input
type="range"
min="0"
max="1"
step="0.1"
value={volume}
onChange={handleVolumeChange}
className="w-24 accent-blue-500"
/>
</div>
<div className="flex items-center space-x-2">
<button
onClick={() => skip(-10)}
className="text-white hover:text-blue-400 transition-colors duration-200"
>
<Replay10Icon className="w-6 h-6" />
</button>
<button
onClick={() => skip(10)}
className="text-white hover:text-blue-400 transition-colors duration-200"
>
<Forward10Icon className="w-6 h-6" />
</button>
</div>
<select
value={playbackRate}
onChange={handlePlaybackRateChange}
className="bg-transparent text-white border border-white rounded p-1 hover:border-blue-400 transition-colors duration-200"
>
<option value="0.5">0.5x</option>
<option value="1">1x</option>
<option value="1.5">1.5x</option>
<option value="2">2x</option>
</select>
</div>
<input
ref={progressRef}
type="range"
min="0"
max="100"
value={progress}
onChange={handleProgressChange}
className="w-full accent-blue-500"
/>
</div>
</div>
</div>