2d旋转木马
.wrapper {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
height: 100vh;
background-image: linear-gradient(to top, #9795f0 0%, #fbc8d4 100%);
overflow: hidden;
}
/* 定义外层容器样式 */
.shell {
position: relative;
/* 相对定位 */
width: 60vw;
/* 宽度占视口宽度的60% */
height: 40vw;
/* 高度占视口高度的40% */
max-width: 380px;
/* 最大宽度为380像素 */
max-height: 250px;
/* 最大高度为250像素 */
margin: 0;
/* 外边距为0 */
color: white;
/* 字体颜色为白色 */
perspective: 1000px;
/* 透视效果,观察者与z=0平面的距离 */
transform-origin: center;
/* 变形原点为中心 */
}
/* 定义内容容器样式 */
.content {
display: flex;
/* 设置为弹性盒子布局 */
justify-content: flex-start;
/* 主轴居中对齐 */
align-items: center;
/* 交叉轴居中对齐 */
position: absolute;
/* 绝对定位 */
width: 500px;
/* 宽度100% */
height: 100%;
overflow: hidden;
/* 高度100% */
transform-origin: center;
/* 变形原点为中心 */
// transform-style: preserve-3d;
/* 保持3D变换 */
// transform: rotateY(0);
/* 变换:沿z轴平移-30vw,绕y轴旋转0度 */
}
/* 定义项目样式 */
.item {
// position: absolute;
position: relative;
/* 绝对定位 */
width: 100px;
flex-shrink: 0;
/* 宽度占视口宽度的60% */
height: 200px;
/* 高度占视口高度的40% */
max-width: 380px;
/* 最大宽度为380像素 */
max-height: 250px;
/* 最大高度为250像素 */
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
/* 设置阴影 */
border-radius: 6px;
/* 边框圆角半径为6像素 */
background-size: cover;
/* 背景图片等比例缩放并覆盖整个容器 */
// backface-visibility: hidden;
transition: all 3s ease;
// background-image: url('./1.webp');
// background-size: cover;
}
import React, { useRef, useState } from "react"
import './index.less';
import { Button } from "antd";
export default function Index() {
const array = new Array(12).fill(1);
const divRef = useRef<HTMLDivElement>(null);
const [count, setCount] = useState(0);
const start = () => {
const count = Math.floor(Math.random() * 10) + array.length;
console.log(count);
setCount(count);
// if (divRef.current) {
// divRef.current.style.transition = 'all 3s ease';
// divRef.current.style.transform = ` rotatey(-${(20 + count) * 36}deg)`;
// setTimeout(() => {
// if (divRef.current) {
// divRef.current.style.transform = ` rotateY(-${count * 36}deg)`;
// divRef.current.style.transition = 'all 0s';
// }
// }, 3000)
// }
}
return <div className="wrapper">
<div className="shell">
<div ref={divRef} className="content">
{
array.map((item, index) => {
const style = { transform: `rotateY(${-((30 * (index - count)) - 90)}deg)`, left: -(count) * 100 - 100 };
return <div key={index} style={style} className="item" >
{index}
<div style={{ background: 'red', height: 10 }}></div>
</div>
})
}
{
array.map((item, index) => {
const style = { transform: `rotateY(${-((30 * (index - count)) - 90)}deg)`, left: -(count) * 100 - 100 };
return <div key={index} style={style} className="item" >
{index}
<div style={{ background: 'red', height: 10 }}></div>
</div>
})
}
{
array.slice(3).map((item, index) => {
const style = { transform: `rotateY(${-((30 * (index - count)) - 90)}deg)`, left: -(count) * 100 - 100 };
return <div key={index} style={style} className="item" >
{index}
<div style={{ background: 'red', height: 10 }}></div>
</div>
})
}
</div>
</div>
<Button onClick={start}>开始</Button>
</div>
}
3d旋转木马
.wrapper {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
height: 100vh;
background-image: linear-gradient(to top, #9795f0 0%, #fbc8d4 100%);
overflow: hidden;
}
.shell {
position: relative;
width: 60vw;
height: 40vw;
max-width: 380px;
max-height: 250px;
margin: 0;
color: white;
perspective: 1000px;
transform-origin: center;
}
.content {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
width: 100%;
height: 100%;
transform-origin: center;
transform-style: preserve-3d;
transform: translateZ(-30vw) rotateY(0);
transition: all 3s;
}
.item {
position: absolute;
width: 60vw;
height: 40vw;
max-width: 380px;
max-height: 250px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
border-radius: 6px;
background-size: cover;
backface-visibility: hidden;
}
import React, { useRef } from "react"
import './index.less';
import { Button } from "antd";
export default function Index() {
const array = new Array(10).fill(1);
const divRef = useRef<HTMLDivElement>(null);
const start = () => {
const count = Math.floor(Math.random() * 10);
if (divRef.current) {
divRef.current.style.transition = 'all 3s';
divRef.current.style.transform = ` translatez(-30vw) rotatey(-${(20 + count) * 36}deg)`;
setTimeout(() => {
if (divRef.current) {
divRef.current.style.transform = `translatez(-30vw) rotateY(-${count * 36}deg)`;
divRef.current.style.transition = 'all 0s';
}
}, 3000)
}
}
return <div className="wrapper">
<div className="shell">
<div ref={divRef} className="content">
{
array.map((item, index) => {
const style = { transform: `rotateY(${360 / array.length * index}deg) translateZ(35vw)` };
return <div key={index} style={style} className="item" />
})
}
<div className="item"></div>
<div className="item"></div>
<div className="item"></div>
</div>
</div>
<Button onClick={start}>开始</Button>
</div>
}