3D旋转选秀盒,收纳刹那间的小美好

简介: 浏览器发展至今,在网页上呈现 3D 效果已经非常简单了,只需要我们用上一个 css 属性,就可以让我们的页面元素拥有 3D 效果,今天我们就使用这个特性来做一个 3D 旋转盒子。

浏览器发展至今,在网页上呈现 3D 效果已经非常简单了,只需要我们用上一个 css 属性,就可以让我们的页面元素拥有 3D 效果,今天我们就使用这个特性来做一个 3D 旋转盒子。

先来体验一下效果:
代码片段

transform-style

上面说到如果需要开启 3D 效果的话,就需要我们使用一个css属性,那就是transform-style,这个属性有两个值:

  • flat:默认值,表示元素的子元素不会被视为 3D 对象,而是被平面化处理。
  • preserve-3d:表示元素的子元素会被视为 3D 对象,保留 3D 效果。

transform-style: preserve-3d 属性定义嵌套元素如何在 3D 空间中呈现。它允许我们在 3D 空间中旋转、缩放和移动元素。

这个属性使用起来很简单,只需要给需要开启 3D 效果的元素添加这个属性即可,如下:

.box {
   
   
    transform-style: preserve-3d;
}

这个属性是可以继承的,也就是说,如果我们给父元素添加了这个属性,那么子元素就会继承这个属性,也就是说子元素也会开启 3D 效果。

3D 盒子

既然我们已经知道了如何开启 3D 效果,那么我们就可以开始做一个 3D 盒子了。

首先我们分析一下 3D 盒子的结构,一个 3D 盒子由 6 个面组成,每个面都是一个div元素,如下:


<div class="container">
    <div class="side1"></div>
    <div class="side2"></div>
    <div class="side3"></div>
    <div class="side4"></div>
    <div class="side5"></div>
    <div class="side6"></div>
</div>

我的命名不规范,不要学我,我是为了图方便。

然后我们给每个面添加样式,如下:

/* 设置盒子的样式,增加3d效果 */
.container {
   
   
    position: relative;
    width: 300px;
    height: 300px;
    transform-style: preserve-3d;
    transform-origin: center center;
}

/* 设置每个面的样式 */
[class*="side"] {
   
   
    position: absolute;
    width: 300px;
    height: 300px;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    box-sizing: border-box;
}

/* 设置每个面的背景图片和位置 */
.side1 {
   
   
    transform: translate3d(0, 0, 150px);
    background-image: url("https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5400559486c24cada8c01f13a72e875a~tplv-k3u1fbpfcp-watermark.image?");
}

.side2 {
   
   
    transform: translate3d(0, 0, -150px) rotateY(180deg);
    background-image: url("https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a02777827b2e4fdaa91107ae5a12c2ab~tplv-k3u1fbpfcp-watermark.image?");
}

.side3 {
   
   
    transform: translate3d(0, -150px, 0) rotateX(90deg);
    background-image: url("https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d6159b78ff704034a4ebf06b7093cadc~tplv-k3u1fbpfcp-watermark.image?");
}

.side4 {
   
   
    transform: translate3d(0, 150px, 0) rotateX(90deg) rotateY(180deg);
    background-image: url("https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c0d3cb14bc8648b7a14d7e795a628f02~tplv-k3u1fbpfcp-watermark.image?");
}

.side5 {
   
   
    transform: translate3d(-150px, 0, 0) rotateY(90deg);
    background-image: url("https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8cadd5ea9f59479996c20b3e5619c4fd~tplv-k3u1fbpfcp-watermark.image?");
}

.side6 {
   
   
    transform: translate3d(150px, 0, 0) rotateY(90deg) rotateY(180deg);
    background-image: url("https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dc92dc8a2a0f42f187e108f803fa903d~tplv-k3u1fbpfcp-watermark.image?");
}

完成之后,上面的 6 个面就会呈现出 3D 效果,但是页面上并没有看到 3D
盒子,这是因为后面的其他面都被挡住了,我们旋转一下就好了,为了效果更明显,我们给container添加一个动画,如下:

.container {
   
   
    /* 省略其他代码 */
    animation: rotate 10s linear infinite;
}

@keyframes rotate {
   
   
    100% {
   
   
        transform: rotate3d(1, 1, 1, 360deg);
    }
}

效果如下:

QQ录屏20221113165157 (1).gif

感觉还不错,但是这个 3D 盒子还是有点单调,就简简单单加个边框吧,如下:

/* 省略其他代码 */
[class*="side"] {
   
   
    border-left: 12px solid #ddd;
    border-right: 12px solid #ddd;
    border-top: 12px solid #eee;
    border-bottom: 12px solid #eee;
}

加点交互

这个盒子好看是好看,但是我想看指定的面,怎么办呢?

那我们就让它可以拖动旋转吧,就这点小需求还不是简简单单,上代码:

const container = document.querySelector('.container');

// 监听鼠标按下事件
document.onmousedown = function (e) {
   
   
    // 停止animation
    container.style.animation = 'none';

    // 记录鼠标按下时的坐标
    const {
   
   clientX, clientY} = e;

    // 监听鼠标移动事件
    document.onmousemove = function (e) {
   
   
        // 计算鼠标移动的距离
        const {
   
   clientX: x, clientY: y} = e;
        const dx = x - clientX;
        const dy = y - clientY;
        const rotateX = dy / 2;
        const rotateY = dx * 2;

        // 获取当前的旋转角度
        const transform = getComputedStyle(container).transform;
        const matrix = transform.match(/matrix(3d)?((.+))/)[2].split(', ') || [];
        const matrixX = Number(matrix[8]);
        const matrixY = Number(matrix[9]);

        // 旋转
        container.style.transform = `rotateX(${rotateX + matrixX}deg) rotateY(${rotateY + matrixY}deg)`;
    }

    // 监听鼠标抬起事件
    document.onmouseup = function () {
   
   
        // 移除鼠标移动事件
        document.onmousemove = null
        document.onmouseup = null

        // 重新开始animation
        container.style.animation = 'rotate 10s linear infinite';
    }
}

完美,现在我们想看哪个面就拖动到哪个面,真不错呀!!!

但是感觉还是差点什么,既然是选秀盒子,那我就需要选呀,那就再加个选秀的交互吧!!!

选秀

选秀的交互其实很简单,就是点击某个面,就让它旋转到正面,这个交互其实就是点击事件,我们只需要监听点击事件,然后旋转到正面就好了,如下:

// 监听每个面的点击事件
document.querySelector('.side1').addEventListener('click', () => {
   
   
    container.style.transform = 'rotateX(360deg) rotateY(360deg)';
    container.style.animation = 'none';
})
document.querySelector('.side2').addEventListener('click', () => {
   
   
    container.style.transform = 'rotateX(0deg) rotateY(180deg)';
    container.style.animation = 'none';
})
document.querySelector('.side3').addEventListener('click', () => {
   
   
    container.style.transform = 'rotateX(270deg) rotateY(0deg)';
    container.style.animation = 'none';
})
document.querySelector('.side4').addEventListener('click', () => {
   
   
    container.style.transform = 'rotateX(90deg) rotateY(180deg)';
    container.style.animation = 'none';
})
document.querySelector('.side5').addEventListener('click', () => {
   
   
    container.style.transform = 'rotateX(0) rotateY(90deg)';
    container.style.animation = 'none';
})
document.querySelector('.side6').addEventListener('click', () => {
   
   
    container.style.transform = 'rotateX(0deg) rotateY(270deg)';
    container.style.animation = 'none';
})

由于每个面的旋转角度都不一样,所以我们需要分别设置,这里就不做优化了,直接写死了。

上面的代码已经可以让我们点击某个面,就让它旋转到正面了,固定到我们选中的妹子,但是既然是我们选中的妹子,那一定要很抢眼才行,要亮灯:

亮灯

亮灯就是直接加个边框闪烁的效果,这个效果其实很简单,就是通过animation来实现,如下:

@keyframes light {
   
   
    0% {
   
   
        box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7);
    }
    70% {
   
   
        box-shadow: 0 0 0 10px rgba(255, 255, 255, 0);
    }
    100% {
   
   
        box-shadow: 0 0 0 0 rgba(255, 255, 255, 0);
    }
}

.light {
   
   
    animation: light 1s infinite;
}

这里我们只需要给选中的面加个类名就好了,如下:

document.querySelector('.side1').addEventListener('click', () => {
   
   
    // 亮灯
    const light = document.querySelector('.light');
    light && light.classList.remove('light');
    e.target.classList.add('light');

    // 省略其他代码
})

ok,大功告成,我们的选秀盒子就完成了,好像也没几行代码,但是这个效果还是很不错的,可以看看效果:

QQ录屏20221113165157 (2).gif

目录
相关文章
|
12月前
|
小程序
做个经典宝石方块游戏
在做了一个月的进阶课程之后,终于又可以回来做游戏了。不得不说,对于我来讲做课程要比做游戏的难的多。做出来是一回事儿,讲出来又是另一回事儿了。尤其是还希望能讲的明白,讲的浅显易懂,感觉还是很难的。不过还好,做课程这件事情也是可以练习的,比如说我现在面对镜头讲一个东西的时候,就比一年前要好很多了。
102 0
|
12月前
|
小程序 搜索推荐 开发者
谈谈宝石方块游戏中的设计
宝石方块是在上一个俄罗斯方块工程的基础上改编的,所以制作起来很快,我只用了不到两天的时间就完成了游戏的功能,后续又花了几天的时间制作游戏的界面,优化游戏的体验。
108 0
137.正六边形螺旋图案
137.正六边形螺旋图案
46 0
自由运动滑块和小球的碰撞检测
自由运动滑块和小球的碰撞检测
89 0
自由运动滑块和小球的碰撞检测
|
前端开发
CSS动画——行走的小人
CSS动画——行走的小人
233 0
CSS动画——行走的小人
一球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在 第10次落地时,共经过多少米?第10次反弹多高
一球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在 第10次落地时,共经过多少米?第10次反弹多高
436 0
一球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在 第10次落地时,共经过多少米?第10次反弹多高
|
机器学习/深度学习
2038. 如果相邻两个颜色均相同则删除当前颜色 : 脑筋急转弯运用题
2038. 如果相邻两个颜色均相同则删除当前颜色 : 脑筋急转弯运用题
坚持写算法题的第四周(五)
坚持写算法题的第四周(五)
坚持写算法题的第四周(五)
坚持写算法题的第四周(四)
坚持写算法题的第四周(四)
坚持写算法题的第四周(四)
坚持写算法题的第四周(一)
坚持写算法题的第四周(一)
坚持写算法题的第四周(一)