小白实战!用JS实现一个3D翻书效果,附上代码

简介: 小白实战!用JS实现一个3D翻书效果,附上代码

前言

今天我们来聊聊,如何实现一个3D翻书的页面,这个效果也是十分的生动和有趣哦,我会结合代码和大家一起制作,看完之后,大家可以选择自行喜欢的图片自己制作哦~也可以复制代码先体验一下效果

首先,我们先来看看我们想要完成的效果

image.png

结构划分

首先,在我们开始制作之前,我们先需要观察一下页面,划分结构,这样也可以将我们的思路打开,这本书的整体我们命名为book p3d,这本书总共有两页,第一页我们叫做front-cover p3d,第二页我们叫做back-cover p3d

我们再仔细观察一下,第一页又可以分为两个部分,正面上有一张图片,我们命名为outside page,用来放置封面的图片,反面写了字,我们可以用inside page p3d flip容器用来存放字体。

接下来到了第二面,<div class="outside page"><div class="inside page p3d">: 这两个div元素分别表示第二页的外部和内部页面。内部页面包括了两个子元素,一个带有类名shadow,另一个带有类名card

我们整体的结构就分完了,接下来我们来看看html的代码

html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="./style.css">
</head>
<body>
  <div class="book p3d">
    <div class="front-cover p3d">
      <div class="inside page p3d flip">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam fermentum nisl quis nulla eleifend dignissim.
          Curabitur varius lobortis tincidunt. Maecenas gravida, nulla quis luctus imperdiet, ipsum nibh consectetur
          ante, in sodales massa tortor eget neque. Donec porta ligula massa, id sagittis est. Ut nisl tellus, faucibus
          nec feugiat ut, laoreet iaculis felis. Suspendisse ultrices mauris vel tellus suscipit commodo. Integer vitae
          tortor erat. Pellentesque non tempor nisi.</p>
      </div>
      <div class="outside page"></div>
    </div>
    <div class="back-cover p3d">
      <div class="outside page"></div>
      <div class="inside page p3d">
        <div class="shadow"></div>
        <div class="card"></div>
      </div>
    </div>
  </div>
  <script src="./index.js"></script>
</body>
</html>

接下来到了CSS部分,我们来写样式

CSS

  1. * {...}: 这是通用样式,将所有HTML元素的默认外边距、内边距、边框、垂直对齐方式进行重置,同时使用盒子模型。这确保了元素的尺寸和布局受到更精确的控制。
*{
    margin: 0;
    padding: 0;
    border: 0;
    vertical-align: baseline;
    box-sizing: border-box;  /* 将容器声明成IE模型 */
  }
  1. body {...}: 这部分样式应用于body元素,设置了页面的字体、透视效果以及背景颜色和背景图像。页面的字体使用Helvetica、Arial、sans-serif字体族,透视效果设置为1000像素,背景颜色渐变从#444到#999。
body{
    height: 100%;
    font: 100%/1.25 Helvetica, arial, sans-serif;
    perspective: 1000px;
    background-color: #444;
    background-image: linear-gradient(to bottom, #444, #999);
  }
  1. .p3d {...}: 这是一个自定义类名,用于设置3D变换效果的元素的样式。它通过transform-style属性来保持3D效果。
.p3d{
    transform-style: preserve-3d;
  }
  1. .book {...}: 这个规则定义了书籍容器的样式。它设置了容器的尺寸、位置、文字颜色以及X轴旋转角度,使书籍看起来有立体感。user-select属性设置为none,以禁止选择文本。
.book{
    width: 300px;
    height: 300px;
    position: absolute;
    left: 50%;
    top: 50%;
    /* transform: translateY(-50%); */
    margin-top: -150px;
    color: #fff;
    -webkit-transform: rotateX(60deg);
    -moz-transform: rotateX(60deg);
    -o-transform: rotateX(60deg);
    user-select: none;
  }
  1. .front-cover {...}: 这部分样式应用于书籍的封面。它定义了封面的鼠标光标样式和Y轴旋转角度。
front-cover{
    cursor: move;
    transform-origin: 0 50%;
    transform: rotateY(0deg);
  }
  1. .page {...}: 这个规则用于定义页面元素的样式,包括尺寸、位置和文本缩进。
.page{
    width: 300px;
    height: 300px;
    padding: 1em;
    position: absolute;
    left: 0;
    top: 0;
    text-indent: 2em;
  }
  1. .inside {...}.outside {...}: 这两个规则分别定义了内部页面和外部页面的样式,其中内部页面的背景颜色设置为#d93e2b,而外部页面的背景颜色为白色。
.inside{
    background-color: #d93e2b;
  }
  .outside{
    background: #fff;
  }
  1. .front-cover .outside {...}: 这个规则应用于封面的外部页面,它设置了背景图片、大小和3D位移效果。
.front-cover .outside{
    background-image: url(https://photo.16pic.com/00/53/63/16pic_5363878_b.jpg);
    background-repeat: no-repeat;
    background-size: cover;
    transform: translateZ(3px);
  }

  
  1. .flip {...}: 这个规则用于创建翻页效果,通过将元素旋转180度来实现。
.flip{
    transform: rotateY(180deg);
  }
  1. .back-cover .outside {...}.back-cover .inside {...}: 这两个规则分别定义了封底的外部和内部页面的样式,类似于封面的设置。
.back-cover .outside{
    transform: translateZ(-3px);
  }
  .back-cover .inside {
    background-color: #d93e2b;
  }
  1. .card {...}.shadow {...}: 这两个规则定义了卡片和阴影的样式,包括尺寸、位置和旋转原点。卡片的背景设置为一个URL链接的图像,而阴影的背景颜色是半透明的黑色。
.card,
  .shadow{
    width: 196px;
    height: 132px;
    position: absolute;
    left: 60px;
    top: 60px;
    transform-origin: 0 100%;
  }
  
  .shadow{
    background-color: rgba(0, 0, 0, 0.5);
  }
  .card{
    background: url(https://foruda.gitee.com/avatar/1677018300688056396/3045275_snail_wn_1620711440.png!avatar200) no-repeat;
    background-size: cover;
  }

图片的话大家放上自己喜欢的图片就可以啦~ 附上完整的CSS代码

*{
    margin: 0;
    padding: 0;
    border: 0;
    vertical-align: baseline;
    box-sizing: border-box;  /* 将容器声明成IE模型 */
  }
  html{
    height: 100%;
  }
  body{
    height: 100%;
    font: 100%/1.25 Helvetica, arial, sans-serif;
    perspective: 1000px;
    background-color: #444;
    background-image: linear-gradient(to bottom, #444, #999);
  }
  .p3d{
    transform-style: preserve-3d;
  }
  
  .book{
    width: 300px;
    height: 300px;
    position: absolute;
    left: 50%;
    top: 50%;
    /* transform: translateY(-50%); */
    margin-top: -150px;
    color: #fff;
    -webkit-transform: rotateX(60deg);
    -moz-transform: rotateX(60deg);
    -o-transform: rotateX(60deg);
    user-select: none;
  }
  .front-cover{
    cursor: move;
    transform-origin: 0 50%;
    transform: rotateY(0deg);
  }
  
  .page{
    width: 300px;
    height: 300px;
    padding: 1em;
    position: absolute;
    left: 0;
    top: 0;
    text-indent: 2em;
  }
  .inside{
    background-color: #d93e2b;
  }
  .outside{
    background: #fff;
  }
  
  .front-cover .outside{
    background-image: url(https://photo.16pic.com/00/53/63/16pic_5363878_b.jpg);
    background-repeat: no-repeat;
    background-size: cover;
    transform: translateZ(3px);
  }
  
  .flip{
    transform: rotateY(180deg);
  }
  
  
  .back-cover .outside{
    transform: translateZ(-3px);
  }
  .back-cover .inside {
    background-color: #d93e2b;
  }
  
  .card,
  .shadow{
    width: 196px;
    height: 132px;
    position: absolute;
    left: 60px;
    top: 60px;
    transform-origin: 0 100%;
  }
  
  .shadow{
    background-color: rgba(0, 0, 0, 0.5);
  }
  .card{
    background: url(https://foruda.gitee.com/avatar/1677018300688056396/3045275_snail_wn_1620711440.png!avatar200) no-repeat;
    background-size: cover;
  }

接下来该到了JS部分了,也是我们此次的重头戏

JS

这个例子中我们使用JS的目的是要监听我们的鼠标,也就是当我们鼠标在书上点时,可以实现翻书的效果,我们先贴上代码

var front = document.getElementsByClassName('front-cover')[0]//byClassName默认以数组返回
var book = document.getElementsByClassName('book')[0]
var card = document.getElementsByClassName('card')[0]
var shadow = document.getElementsByClassName('shadow')[0]
var hold= false
var clamp = function(val,min,max){
    return Math.max(min,Math.min(val,max))
}
//onmousedown监听鼠标是否点击,是否按下
front.onmousedown = function(){
    hold = true
}
window.onmouseup=function(){
    hold = false
}
window.onmousemove=function(e){
    if(hold){
        //修改左半本书的角度,卡片旋转,阴影倾斜
        //鼠标在x轴移动的距离控制角度
        var deg = clamp((window.innerWidth/2-e.x+300)/300 * -90,-180,0)
        front.style.transform = `rotateY(${deg}deg)`
        //整本书立起来60+deg/8
        book.style.transform=`rotateX(${deg/8+60}deg)`
        //卡片立起来deg/2
        card.style.transform = `rotateX(${deg/2}deg)`
        //阴影倾斜的角度deg/8
        shadow.style.transform = `skew(${deg/8}deg)`
    }
}
  1. var front = document.getElementsByClassName('front-cover')[0]: 这行代码通过getElementsByClassName方法获取页面中具有类名front-cover的元素,并将第一个匹配的元素存储在front变量中。这个元素通常是书籍的封面。
  2. var book = document.getElementsByClassName('book')[0]: 同样,这行代码获取页面中具有类名book的元素,通常是整本书的容器,然后将其存储在book变量中。
  3. var card = document.getElementsByClassName('card')[0]: 这行代码获取类名为card的元素,通常是卡片,然后将其存储在card变量中。
  4. var shadow = document.getElementsByClassName('shadow')[0]: 同样,这行代码获取具有类名shadow的元素,通常表示阴影,然后将其存储在shadow变量中。
  5. var hold = false: 这行代码创建一个布尔变量hold,用于标记鼠标是否按下。初始值设置为false,表示鼠标未按下。
  6. var clamp = function(val, min, max) {...}: 这是一个自定义的JavaScript函数,用于将给定的值val限制在指定的最小值min和最大值max之间。如果val小于min,则返回min;如果val大于max,则返回max;否则返回val本身。
  7. front.onmousedown = function() {...}: 这行代码为封面元素front添加一个鼠标按下事件监听器。当用户按下鼠标按钮时,触发这个事件处理函数,将hold变量设置为true,表示鼠标按下。
  8. window.onmouseup = function() {...}: 这行代码为window对象添加一个鼠标松开事件监听器。当用户释放鼠标按钮时,触发这个事件处理函数,将hold变量设置为false,表示鼠标松开。
  9. window.onmousemove = function(e) {...}: 这行代码为window对象添加一个鼠标移动事件监听器。当用户移动鼠标时,触发这个事件处理函数。在事件处理函数中,首先检查hold变量的值,如果鼠标按下(holdtrue),则执行下面的代码块。
  10. var deg = clamp((window.innerWidth / 2 - e.x + 300) / 300 * -90, -180, 0): 这行代码计算一个角度值deg,该角度值受鼠标在x轴上的移动距离影响。clamp函数用来确保deg在指定范围内,最小值为-180度,最大值为0度。
  11. front.style.transform = rotateY(${deg}deg);: 这行代码通过修改front元素的transform属性,将封面元素绕Y轴旋转,角度由deg值控制。这实现了翻页效果。
  12. book.style.transform = rotateX(${deg/8+60}deg);: 这行代码修改整本书的容器元素booktransform属性,使书本立起来,角度由deg值的八分之一加60度控制。
  13. card.style.transform = rotateX(${deg/2}deg);: 这行代码修改卡片元素cardtransform属性,使卡片立起来,角度由deg值的二分之一控制。
  14. shadow.style.transform = skew(${deg/8}deg);: 这行代码修改阴影元素shadowtransform属性,使阴影产生倾斜效果,角度由deg值的八分之一控制。

总之,这段代码创建了一个具有3D翻页效果的交互式书籍,用户可以通过拖动鼠标来实现书页的翻动,同时调整书页、卡片和阴影的角度,以营造真实的书本翻页效果。

现在,我们这个3D翻书效果已经制作完成啦~小伙伴们赶快去试试吧,也可以分享给你们的小伙伴一起观看一起完成呀

image.png

今天的内容就到这啦,如果你觉得小编写的还不错的话,或者对你有所启发,请给小编一个辛苦的赞吧

相关文章
|
7月前
|
人工智能 自然语言处理 JavaScript
通义灵码2.5实战评测:Vue.js贪吃蛇游戏一键生成
通义灵码基于自然语言需求,快速生成完整Vue组件。例如,用Vue 2和JavaScript实现贪吃蛇游戏:包含键盘控制、得分系统、游戏结束判定与Canvas动态渲染。AI生成的代码符合规范,支持响应式数据与事件监听,还能进阶优化(如增加启停按钮、速度随分数提升)。传统需1小时的工作量,使用通义灵码仅10分钟完成,大幅提升开发效率。操作简单:安装插件、输入需求、运行项目即可实现功能。
385 4
 通义灵码2.5实战评测:Vue.js贪吃蛇游戏一键生成
|
3月前
|
JavaScript 前端开发 安全
【逆向】Python 调用 JS 代码实战:使用 pyexecjs 与 Node.js 无缝衔接
本文介绍了如何使用 Python 的轻量级库 `pyexecjs` 调用 JavaScript 代码,并结合 Node.js 实现完整的执行流程。内容涵盖环境搭建、基本使用、常见问题解决方案及爬虫逆向分析中的实战技巧,帮助开发者在 Python 中高效处理 JS 逻辑。
|
5月前
|
JavaScript 前端开发 算法
流量分发代码实战|学会用JS控制用户访问路径
流量分发工具(Traffic Distributor),又称跳转器或负载均衡器,可通过JavaScript按预设规则将用户随机引导至不同网站,适用于SEO优化、广告投放、A/B测试等场景。本文分享一段不到百行的JS代码,实现智能、隐蔽的流量控制,并附完整示例与算法解析。
151 1
|
6月前
|
JavaScript 前端开发
怀孕b超单子在线制作,p图一键生成怀孕,JS代码装逼娱乐
模拟B超单的视觉效果,包含随机生成的胎儿图像、医疗文本信息和医院标志。请注意这仅用于前端开发学习
|
6月前
|
JavaScript
JS代码的一些常用优化写法
JS代码的一些常用优化写法
110 0
|
8月前
|
存储 JavaScript 前端开发
在NodeJS中使用npm包进行JS代码的混淆加密
总的来说,使用“javascript-obfuscator”包可以帮助我们在Node.js中轻松地混淆JavaScript代码。通过合理的配置,我们可以使混淆后的代码更难以理解,从而提高代码的保密性。
697 9
|
7月前
|
JavaScript 数据可视化 前端开发
three.js简单实现一个3D三角函数学习理解
1.Three.js简介 Three.js是一个基于JavaScript编写的开源3D图形库,利用WebGL技术在网页上渲染3D图形。它提供了许多高级功能,如几何体、纹理、光照、阴影等,以便开发者能够快速地创建复杂且逼真的3D场景。同时,Three.js还具有很好的跨平台和跨浏览器兼容性,让用户无需安装任何插件就可以在现代浏览器上观看3D内容。
235 0
|
9月前
|
前端开发 JavaScript
【Javascript系列】Terser除了压缩代码之外,还有优化代码的功能
Terser 是一款广泛应用于前端开发的 JavaScript 解析器和压缩工具,常被视为 Uglify-es 的替代品。它不仅能高效压缩代码体积,还能优化代码逻辑,提升可靠性。例如,在调试中发现,Terser 压缩后的代码对删除功能确认框逻辑进行了优化。常用参数包括 `compress`(启用压缩)、`mangle`(变量名混淆)和 `output`(输出配置)。更多高级用法可参考官方文档。
632 11
|
9月前
|
JavaScript 前端开发 算法
JavaScript 中通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能,JS中排序算法的使用详解(附实际应用代码)
Array.sort() 是一个功能强大的方法,通过自定义的比较函数,可以处理各种复杂的排序逻辑。无论是简单的数字排序,还是多字段、嵌套对象、分组排序等高级应用,Array.sort() 都能胜任。同时,通过性能优化技巧(如映射排序)和结合其他数组方法(如 reduce),Array.sort() 可以用来实现高效的数据处理逻辑。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
9月前
|
JavaScript 前端开发 API
JavaScript中通过array.map()实现数据转换、创建派生数组、异步数据流处理、复杂API请求、DOM操作、搜索和过滤等,array.map()的使用详解(附实际应用代码)
array.map()可以用来数据转换、创建派生数组、应用函数、链式调用、异步数据流处理、复杂API请求梳理、提供DOM操作、用来搜索和过滤等,比for好用太多了,主要是写法简单,并且非常直观,并且能提升代码的可读性,也就提升了Long Term代码的可维护性。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

热门文章

最新文章