本文详细解析如何利用JavaScript结合CSS3 Transform属性,实现一个简易的3D立体翻书交互模型。内容涵盖HTML结构构建、CSS3D样式设置以及JS鼠标事件监听与坐标计算,通过拖拽封面实现书页旋转与阴影变化,适合前端初学者学习3D变换与交互逻辑。
序言
本文旨在展示一个轻松有趣的JavaScript小案例,首先通过实验效果图直观了解最终实现的效果。

在展示效果后,接下来将直接提供完整的实现代码。
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" rel="external nofollow" rel="external nofollow" >
</head>
<body>
<div class="book p3d">
<div class="front-cover p3d">
<div class="inside page p3d flip">
<p>瓦罗兰特(VALORANT)是一款第一人称FPS游戏。
与传统FPS游戏不同,游戏中每个角色都拥有其不一样的技能,小队角色之间的技能互相搭配进攻能发挥更强的作用。
背景设定:在近未来的地球世界里,全球范围遭遇了一个重要的事件,名为First Light(原初之光),这个事件改变了地球,带来了生命、科技和政府运行的大转变。
部分地球人在这个事件中获得了超能力,这些拥有超能力的人们被称为“Radiants(辐射人)”,意味着他们是被原初之光辐射从而获得了超能力。</p>
</div>
<div class="outside page"></div>
</div>
<div class="back-cover p3d">
<div class="outside page p3d">
<div class="inside page p3d">
<div class="shadow"></div>
<div class="card"></div>
</div>
</div>
</div>
</div>
<script src="index.js"></script>
</body>
</html>
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: #2a0303;
}
.outside{
background-color: #fff;
}
.front-cover .outside{
background-image: url(https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.nga.178.com%2Fattachments%2Fmon_202006%2F02%2FjoQ5-38t6XlZ5pT3cS2yo-1o0.png&refer=http%3A%2F%2Fimg.nga.178.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1700461884&t=fb89517f74280d519c31d1b97adb1af3);
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: #1e0000;
}
.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-image: url(https://images.9k9k.com/m/gamelib/202011/90947_zkyz.jpg);
background-size: cover;
transform-origin: 0 100%;
}
JS代码
var front = document.getElementsByClassName('front-cover')[0]
var book = document.getElementsByClassName('book')[0]
var card = document.getElementsByClassName('card')[0]
var shadow = document.getElementsByClassName('shadow')[0]
var hlod = false
var clamp = function(val,min,max){
return Math.max(min,Math.min(val,max))
}
//鼠标是否按下
front.onmousedown = function(){
hlod = true
}
//在window上监听鼠标松开
window.onmouseup = function(){
hlod = false
}
window.onmousemove = function(e){
if(hlod){
//修改左半边书的角度,卡片旋转,阴影倾斜
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(${60 + deg / 8}deg)`
//卡片 deg / 2
card.style.transform = `rotateX(${deg / 3}deg)`
//阴影倾斜 deg / 8 (css样式倾斜)
shadow.style.transform = `skew(${deg / 8}deg)`
}
}
console.log(front);
var front = document.getElementsByClassName('front-cover')[0]
var book = document.getElementsByClassName('book')[0]
var card = document.getElementsByClassName('card')[0]
var shadow = document.getElementsByClassName('shadow')[0]
var hlod = false
var clamp = function(val,min,max){
return Math.max(min,Math.min(val,max))
}
//鼠标是否按下
front.onmousedown = function(){
hlod = true
}
//在window上监听鼠标松开
window.onmouseup = function(){
hlod = false
}
window.onmousemove = function(e){
if(hlod){
//修改左半边书的角度,卡片旋转,阴影倾斜
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(${60 + deg / 8}deg)`
//卡片 deg / 2
card.style.transform = `rotateX(${deg / 3}deg)`
//阴影倾斜 deg / 8 (css样式倾斜)
shadow.style.transform = `skew(${deg / 8}deg)`
}
}
console.log(front);
代码解释
HTML部分
引入文件
项目中创建的CSS样式文件和JavaScript脚本均需正确引入到HTML文件中才能生效。
在HTML文档的head标签内,使用link元素引入外部CSS样式表文件。
<head>
<link rel="stylesheet" href="style.css" rel="external nofollow" rel="external nofollow" >
</head>
在body标签末尾,使用script标签引入JavaScript交互脚本文件。
<body>
<script src="index.js"></script>
</body>
HTML框架构建(BEM命名法)
我们将整本书的结构划分为多个部分,整体容器命名为book,并根据视觉效果和功能需求将其拆分为不同的子模块。
<div class="book p3d">
<div class="front-cover p3d">
<div class="inside page p3d flip">
<p>
</div>
<div class="outside page"></div>
</div>
<div class="back-cover p3d">
<div class="outside page p3d">
<div class="inside page p3d">
<div class="shadow"></div>
<div class="card"></div>
</div>
</div>
</div>
</div>
结构划分完成后,后续工作主要集中于CSS样式的编写与调整。
CSS样式编写
*{
margin: 0;
padding: 0;
border: 0;
vertical-align: baseline;
box-sizing: border-box; /*将容器声明成IE模型*/
}
浏览器默认会对body元素添加内外边距,因此需将其重置为0。此外,为了确保页面效果完美呈现,我们将盒模型设置为border-box(即IE盒模型),使宽度和高度包含边框和内边距。
-webkit-transform: rotateX(60deg);
-moz-transform: rotateX(60deg);
-o-transform: rotateX(60deg);
代码中使用了-webkit-transform、-moz-transform、-o-transform等浏览器前缀以兼容不同内核的浏览器。现代主流浏览器大多已原生支持transform属性,通常可省略这些前缀。
此处将元素绕X轴旋转60度,但具体角度数值需根据页面实际呈现效果及其他样式属性进行微调确定。
.page{
width: 300px;
height: 300px;
padding: 1em;
position: absolute;
left: 0;
top: 0;
text-indent: 2em;
}
padding: 1em; em是指相对父容器大小
position: absolute;会导致其脱离文档流
JS交互功能编写
这段JavaScript代码的核心功能是监听鼠标对前封面(front)的拖拽操作,通过触发相应事件来控制页面元素的旋转角度,从而实现逼真的交互效果。
var front = document.getElementsByClassName('front-cover')[0]
var book = document.getElementsByClassName('book')[0]
var card = document.getElementsByClassName('card')[0]
var shadow = document.getElementsByClassName('shadow')[0]
具体实现中,首先通过document.getElementsByClassName()方法分别获取front、book、card和shadow这四个DOM元素。
front.onmousedown = function(){
hlod = true
}
同时定义了一个名为hlod的变量,用于标识鼠标当前是否处于按下状态。
front.onmousedown = function(){
hlod = true
}
window.onmouseup = function(){
hlod = false
}
代码为front元素绑定了mousedown事件以监听鼠标按下动作,按下时将hlod设为true。随后,在window对象上绑定mousemove和mouseup事件,分别监听鼠标移动和松开动作。当鼠标移动且hlod为true时,根据当前鼠标位置计算deg值,并利用clamp()函数将deg限制在-180到0之间。最后,通过修改各元素的transform属性实现立体旋转:front元素绕Y轴旋转deg度,book元素绕X轴旋转60 + deg / 8度,card元素绕X轴旋转deg / 3度,shadow元素倾斜deg / 8度。此处使用模板字面量语法构建包含变量的字符串,以方便设置transform属性值。
最后,使用console.log()函数输出front元素的信息,便于开发者检查与调试。
以上就是利用JavaScript实现简单3D开关书本模型的详细内容,更多关于JavaScript 3D开关书本的资料请关注本站其它相关文章!