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

目录
相关文章
|
存储 缓存 固态存储
你还不懂硬盘,内存和CPU的关系 ?(程序员入门)
你好我是辰兮,很高兴你能来阅读,本篇文章小结了硬盘,内存和CPU的关系,献给初学者,分享获取新知,大家共同进步。
1347 0
你还不懂硬盘,内存和CPU的关系 ?(程序员入门)
|
3月前
|
机器学习/深度学习 算法 搜索推荐
从零开始构建图注意力网络:GAT算法原理与数值实现详解
本文详细解析了图注意力网络(GAT)的算法原理和实现过程。GAT通过引入注意力机制解决了图卷积网络(GCN)中所有邻居节点贡献相等的局限性,让模型能够自动学习不同邻居的重要性权重。
515 0
从零开始构建图注意力网络:GAT算法原理与数值实现详解
|
数据采集 存储 监控
实现自动化数据抓取:使用Node.js操控鼠标点击与位置坐标
本文介绍了如何使用Node.js和Puppeteer实现自动化数据抓取,特别是针对新闻网站“澎湃新闻”。通过设置代理IP、User-Agent和Cookie,提高爬虫的效率和隐蔽性,避免被网站封锁。代码示例展示了如何模拟鼠标点击、键盘输入等操作,抓取并整理新闻数据,适用于需要规避IP限制和突破频率限制的场景。
555 10
Vue3使用createVNode和render函数实现仿 Antd 加载动效
本文展示了如何在Vue3项目中使用`createVNode`和`render`函数实现一个仿Ant Design加载动效的自定义组件,并提供了详细的实现代码和使用示例。
611 0
Vue3使用createVNode和render函数实现仿 Antd 加载动效
|
存储 算法
【数据结构和算法】图的各类概念与图的存储结构(还有十字链表与邻接多重表的介绍)
【数据结构和算法】图的各类概念与图的存储结构(还有十字链表与邻接多重表的介绍)
564 0
【数据结构和算法】图的各类概念与图的存储结构(还有十字链表与邻接多重表的介绍)
|
编解码 网络协议 芯片
以太网口硬件知识分享
该文介绍了网络通信的基本原理,涉及PHY、MAC和RJ45接口的角色。PHY芯片负责物理层的信号处理,MAC则处理帧同步和MAC地址。网络通信中,MAC通常集成在CPU内,PHY通过MDIO总线与MAC交互,配置PHY芯片实现不同模式和功能。文中还提到了常见的网络信号模式(如MII、RMII)及其差异,并指出网络变压器的作用。此外,文章详细解析了KSZ8081RNB PHY芯片的电路原理,包括底板和扩展板的网口设计,以及网口电路和PCB设计的注意事项。最后,提供了网口问题的排查思路。
611 0
|
前端开发
告别屎山!!!WebSocket 的极致封装, 写好代码竟如此简单
告别屎山!!!WebSocket 的极致封装, 写好代码竟如此简单
460 0
|
前端开发 JavaScript 容器
前端炫技合集,简单的TODoList,简单的技术,实现不简单的效果
前端炫技合集,简单的TODoList,简单的技术,实现不简单的效果
423 0
|
前端开发 中间件 索引
【源码共读】洋葱模型 koa-compose
【源码共读】洋葱模型 koa-compose
259 0