JS特效篇:3D放映机轮播图

JS特效篇:3D放映机轮播图

  • 前言
  • 效果预览
  • 代码实现
  • 代码说明
    • HTML结构
      • HTML结构说明
    • CSS样式
      • CSS样式说明
    • JS逻辑
      • JS逻辑说明
  • 结语

前言

本文将讲述如何通过CSS+JS,实现一个3D放映机轮播图,图片以放映机胶片卷轴的形式呈环形排列,模拟真实胶片转动效果,并详细讲解其中的原理和关键代码。

效果预览

代码实现

DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>3D放映机轮播图title>
		<style>
			* {
				margin: 0;
				padding: 0;
				box-sizing: border-box;
			}

			body {
				display: flex;
				background-color: #1a1a1a;
				justify-content: center;
				align-items: center;
				height: 100vh;
			}

			.film-container {
				position: relative;
				width: 800px;
				height: 500px;
				perspective: 1000px;
			}

			.film-reel {
				position: relative;
				width: 100%;
				height: 100%;
				transform-style: preserve-3d;
				animation: rotateFilm 20s linear infinite;
			}

			.film-frame {
				position: absolute;
				width: 520px;
				height: 400px;
				left: 50px;
				top: 50px;
				backface-visibility: hidden;
				transform-origin: center;
				display: flex;
				justify-content: center;
				align-items: center;
				border: 10px solid #333;
				box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
				overflow: hidden;
				background-color: #000;
			}

			.film-frame img {
				max-width: 100%;
				max-height: 100%;
				object-fit: contain;
				filter: sepia(30%) contrast(1.2);
			}

			/* 控制每个胶片帧的位置 */
			.film-frame:nth-child(1) {
				transform: rotateY(0deg) translateZ(450px);
			}

			.film-frame:nth-child(2) {
				transform: rotateY(60deg) translateZ(450px);
			}

			.film-frame:nth-child(3) {
				transform: rotateY(120deg) translateZ(450px);
			}

			.film-frame:nth-child(4) {
				transform: rotateY(180deg) translateZ(450px);
			}

			.film-frame:nth-child(5) {
				transform: rotateY(240deg) translateZ(450px);
			}

			.film-frame:nth-child(6) {
				transform: rotateY(300deg) translateZ(450px);
			}

			/* 电影胶片旋转动画 */
			@keyframes rotateFilm {
				0% {
					transform: rotateY(0deg);
				}

				100% {
					transform: rotateY(360deg);
				}
			}

			/* 控制按钮样式 */
			.controls {
				position: absolute;
				bottom: 20px;
				left: 50%;
				transform: translateX(-50%);
				display: flex;
				gap: 10px;
				z-index: 30;
			}

			.controls button {
				background-color: #333;
				color: white;
				border: none;
				padding: 8px 15px;
				border-radius: 5px;
				cursor: pointer;
				transition: background-color 0.3s;
				font-size: 14px;
			}

			.controls button:hover {
				background-color: #555;
			}
		style>
	head>
	<body>

		<div class="film-container">
			<div class="film-reel">
				<div class="film-frame"><img src="https://picsum.photos/800/400?random=1" alt="Film Frame 1">div>
				<div class="film-frame"><img src="https://picsum.photos/800/400?random=2" alt="Film Frame 2">div>
				<div class="film-frame"><img src="https://picsum.photos/800/400?random=3" alt="Film Frame 3">div>
				<div class="film-frame"><img src="https://picsum.photos/800/400?random=4" alt="Film Frame 4">div>
				<div class="film-frame"><img src="https://picsum.photos/800/400?random=5" alt="Film Frame 5">div>
				<div class="film-frame"><img src="https://picsum.photos/800/400?random=6" alt="Film Frame 6">div>
			div>

			
			<div class="controls">
				<button id="playBtn"><i class="fa fa-play">i> 播放button>
				<button id="pauseBtn"><i class="fa fa-pause">i> 暂停button>
				<button id="speedBtn"><i class="fa fa-tachometer">i> 加速button>
			div>
		div>

		<script>
			// 获取元素和变量
			const filmReel = document.querySelector('.film-reel');
			const playBtn = document.getElementById('playBtn');
			const pauseBtn = document.getElementById('pauseBtn');
			const speedBtn = document.getElementById('speedBtn');
			let rotationSpeed = 20; // 默认速度
			let isPlaying = true;
			let rotationInterval;

			// 更新动画
			function updateAnimation() {
				filmReel.style.animation = `rotateFilm ${rotationSpeed}s linear infinite`;
			}

			// 播放/暂停功能
			playBtn.addEventListener('click', () => {
				if (!isPlaying) {
					filmReel.style.animationPlayState = 'running';
					isPlaying = true;
				}
			});

			pauseBtn.addEventListener('click', () => {
				if (isPlaying) {
					filmReel.style.animationPlayState = 'paused';
					isPlaying = false;
				}
			});

			// 调整速度功能
			speedBtn.addEventListener('click', () => {
				rotationSpeed = rotationSpeed > 5 ? rotationSpeed - 5 : 20;
				updateAnimation();
			});

			// 初始化动画
			updateAnimation();
		script>

	body>
html>

代码说明

HTML结构

<div class="film-container">
	<div class="film-reel">
		<div class="film-frame"><img src="https://picsum.photos/800/400?random=1" alt="Film Frame 1">div>
		<div class="film-frame"><img src="https://picsum.photos/800/400?random=2" alt="Film Frame 2">div>
		<div class="film-frame"><img src="https://picsum.photos/800/400?random=3" alt="Film Frame 3">div>
		<div class="film-frame"><img src="https://picsum.photos/800/400?random=4" alt="Film Frame 4">div>
		<div class="film-frame"><img src="https://picsum.photos/800/400?random=5" alt="Film Frame 5">div>
		<div class="film-frame"><img src="https://picsum.photos/800/400?random=6" alt="Film Frame 6">div>
	div>

	
	<div class="controls">
		<button id="playBtn"><i class="fa fa-play">i> 播放button>
		<button id="pauseBtn"><i class="fa fa-pause">i> 暂停button>
		<button id="speedBtn"><i class="fa fa-tachometer">i> 加速button>
	div>
div>

HTML结构说明

上述代码中:

  1. film-container 为放映机容器,控制透视距离。
  2. .film-reel 作为图片切换放映的实际载体。
  3. 每个 .film-frame 代表一张图片(胶片)。

CSS样式

<style>
	* {
		margin: 0;
		padding: 0;
		box-sizing: border-box;
	}

	body {
		display: flex;
		background-color: #1a1a1a;
		justify-content: center;
		align-items: center;
		height: 100vh;
	}

	.film-container {
		position: relative;
		width: 800px;
		height: 500px;
		perspective: 1000px;
	}

	.film-reel {
		position: relative;
		width: 100%;
		height: 100%;
		transform-style: preserve-3d;
		animation: rotateFilm 20s linear infinite;
	}

	.film-frame {
		position: absolute;
		width: 520px;
		height: 400px;
		left: 50px;
		top: 50px;
		backface-visibility: hidden;
		transform-origin: center;
		display: flex;
		justify-content: center;
		align-items: center;
		border: 10px solid #333;
		box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
		overflow: hidden;
		background-color: #000;
	}

	.film-frame img {
		max-width: 100%;
		max-height: 100%;
		object-fit: contain;
		filter: sepia(30%) contrast(1.2);
	}

	/* 控制每个胶片帧的位置 */
	.film-frame:nth-child(1) {
		transform: rotateY(0deg) translateZ(450px);
	}

	.film-frame:nth-child(2) {
		transform: rotateY(60deg) translateZ(450px);
	}

	.film-frame:nth-child(3) {
		transform: rotateY(120deg) translateZ(450px);
	}

	.film-frame:nth-child(4) {
		transform: rotateY(180deg) translateZ(450px);
	}

	.film-frame:nth-child(5) {
		transform: rotateY(240deg) translateZ(450px);
	}

	.film-frame:nth-child(6) {
		transform: rotateY(300deg) translateZ(450px);
	}

	/* 电影胶片旋转动画 */
	@keyframes rotateFilm {
		0% {
			transform: rotateY(0deg);
		}

		100% {
			transform: rotateY(360deg);
		}
	}

	/* 控制按钮样式 */
	.controls {
		position: absolute;
		bottom: 20px;
		left: 50%;
		transform: translateX(-50%);
		display: flex;
		gap: 10px;
		z-index: 30;
	}

	.controls button {
		background-color: #333;
		color: white;
		border: none;
		padding: 8px 15px;
		border-radius: 5px;
		cursor: pointer;
		transition: background-color 0.3s;
		font-size: 14px;
	}

	.controls button:hover {
		background-color: #555;
	}
style>

CSS样式说明

在上述代码中:

  1. .film-container 通过 perspective: 1000px 建立 3D 透视效果。
  2. .film-reel 使用 transform-style: preserve-3d 保留子元素的 3D 变换。
  3. .film-frame通过 backface-visibility: hidden 避免图片翻转时显示背面,并通过transform-origin: center 确保围绕中心旋转。
  4. .film-frame:nth-child控制每个胶片帧的位置,子元素按60度递增,形成正六边形环形。

JS逻辑

<script>
	// 获取元素和变量
	const filmReel = document.querySelector('.film-reel');
	const playBtn = document.getElementById('playBtn');
	const pauseBtn = document.getElementById('pauseBtn');
	const speedBtn = document.getElementById('speedBtn');
	let rotationSpeed = 20; // 默认速度
	let isPlaying = true;
	let rotationInterval;

	// 更新动画
	function updateAnimation() {
		filmReel.style.animation = `rotateFilm ${rotationSpeed}s linear infinite`;
	}

	// 播放/暂停功能
	playBtn.addEventListener('click', () => {
		if (!isPlaying) {
			filmReel.style.animationPlayState = 'running';
			isPlaying = true;
		}
	});

	pauseBtn.addEventListener('click', () => {
		if (isPlaying) {
			filmReel.style.animationPlayState = 'paused';
			isPlaying = false;
		}
	});

	// 调整速度功能
	speedBtn.addEventListener('click', () => {
		rotationSpeed = rotationSpeed > 5 ? rotationSpeed - 5 : 20;
		updateAnimation();
	});

	// 初始化动画
	updateAnimation();
script>

JS逻辑说明

上述代码中:

  1. 通过updateAnimation() 方法动态调整旋转速度。

结语

本文主要介绍了如何通过CSS+JS实现一个3D放映机轮播图,在后面的文章中,我会继续探讨其他类型的轮播图,你还知道哪些轮播图?欢迎在评论区留言分享!

你可能感兴趣的:(#,JS页面特效,javascript,3d,前端,轮播图,放映机轮播图)