3D轮播图实现

3D轮播图实现

1.效果展示

2.html部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="carousel">
<img src="./img/prev.png" alt="" class="prev">
<img src="./img/next.png" alt="" class="next">

<div class="carousel-list">
<img src="./img/1.png" alt="" class="carousel-item">
<img src="./img/2.png" alt="" class="carousel-item">
<img src="./img/3.png" alt="" class="carousel-item">
<img src="./img/4.png" alt="" class="carousel-item">
<img src="./img/5.png" alt="" class="carousel-item">
<img src="./img/6.png" alt="" class="carousel-item">
<img src="./img/7.png" alt="" class="carousel-item">
<img src="./img/8.png" alt="" class="carousel-item">
<img src="./img/9.png" alt="" class="carousel-item">
</div>
</div>

html部分没有什么好说的,主要由两个箭头和若干张图片组成

3.css部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<style>
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
body{
background-color: black;
}
.carousel{
position: relative;
margin-top: 100px;
}
.carousel-list{
height: 400px;
perspective: 500px;
}
.carousel-item{
width: 600px;
height: 400px;
position: absolute;
transition: all 0.4s;
top: 0;
left: 50%;
margin-left:-300px;
cursor: pointer;
border-radius: 15px;
}
.prev, .next{
width: 100px;
height: 100px;
position: absolute;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
padding: 10px;
border-radius: 15px;
transition: all 0.4s;
background-color: rgba(255, 255, 255, 0.5);
z-index: 100;
}
.prev:hover, .next:hover{
background-color: rgba(255, 255, 255, 1);
}
.prev{
left: 20px;
}
.next{
right: 20px;
}

</style>

perspective主要是用来做3D透视效果的,给需要透视的元素的父元素加上该属性后,在对需要透视的元素加上 transform : rotateY(45deg) 才能有透视效果,这个值越大透视深度越浅,值越小透视深度越深。

注意:在对img元素进行居中的时候,给他们加上了绝对定位,按照正常情况代码应该是这样的

1
2
3
4
5
position: absolute;
transition: all 0.4s;
top: 0;
left: 50%;
transform:translateX(-50%)

但是,后续需要动态改变transform,就会导致css中的transform不生效,故采用了将margin-left的值设置为元素宽度的一半来实现居中效果

4.js部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<script>
const items = document.querySelectorAll(".carousel-item")
let index = 3;

const prev = document.querySelector(".prev")
const next = document.querySelector(".next")

function layout(){
const xoffsetStep = 150 //表示两张图片的横向间隔
const scaleStep = 0.6 //表示两张图片的缩放比例
const opacityStep = 0.7 //表示图片透明度递减的速度

for(let i=0;i<items.length;i++){
const item = items[i] //获取每一张图片
const dis = Math.abs(i - index) //获取当前图片与中心图片的距离,并且取正数
const scale = scaleStep ** dis //计算图片需要缩放的比例 使用的是指数运算
const opacity = opacityStep ** dis //计算图片需要透明度的比例 使用的是指数运算
const sign = Math.sign(i - index) //判断图片是在中心图片的左边还是右边 sign的值返回的是-1或者1
const rotateY = i==index ? 0 : 30 * -sign //判断图片是在中心图片的左边还是右边,如果是中心图片则不旋转,否则旋转30度
let xoffset = (i - index) * xoffsetStep //计算图片的横向偏移量,每张图片之间是有一定距离的


//设置计算出来的样式
item.style.transform = `translateX(${xoffset}px) scale(${scale}) rotateY(${rotateY}deg)`
item.style.zIndex = items.length - dis
item.style.opacity = opacity
}
}

//最初先调用一下layout函数
layout()

//给prev和next按钮添加点击事件
prev.addEventListener("click", () => {
index--;
if(index < 0){
index = items.length - 1;
}
layout();
})

//给prev和next按钮添加点击事件
next.addEventListener("click", () => {
index++;
if(index > items.length - 1){
index = 0;
}
layout();
})

//给每一张图片添加点击事件
items.forEach((item, i) => {
item.addEventListener("click", () => {
index = i;
layout();
})
})
</script>

5.完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="carousel">
<img src="./img/prev.png" alt="" class="prev">
<img src="./img/next.png" alt="" class="next">

<div class="carousel-list">
<img src="./img/1.png" alt="" class="carousel-item">
<img src="./img/2.png" alt="" class="carousel-item">
<img src="./img/3.png" alt="" class="carousel-item">
<img src="./img/4.png" alt="" class="carousel-item">
<img src="./img/5.png" alt="" class="carousel-item">
<img src="./img/6.png" alt="" class="carousel-item">
<img src="./img/7.png" alt="" class="carousel-item">
<img src="./img/8.png" alt="" class="carousel-item">
<img src="./img/9.png" alt="" class="carousel-item">
</div>
</div>
</body>

<style>
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
body{
background-color: black;
}
.carousel{
position: relative;
margin-top: 100px;
}
.carousel-list{
height: 400px;
perspective: 400px;

}
.carousel-item{
width: 600px;
height: 400px;
position: absolute;
transition: all 0.4s;
top: 0;
left: 50%;
margin-left:-300px;
cursor: pointer;
border-radius: 15px;
}
.prev, .next{
width: 100px;
height: 100px;
position: absolute;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
padding: 10px;
border-radius: 15px;
transition: all 0.4s;
background-color: rgba(255, 255, 255, 0.5);
z-index: 100;
}
.prev:hover, .next:hover{
background-color: rgba(255, 255, 255, 1);
}
.prev{
left: 20px;
}
.next{
right: 20px;
}

</style>

<script>
const items = document.querySelectorAll(".carousel-item")
let index = 3;

const prev = document.querySelector(".prev")
const next = document.querySelector(".next")

function layout(){
const xoffsetStep = 150 //表示两张图片的横向间隔
const scaleStep = 0.6 //表示两张图片的缩放比例
const opacityStep = 0.7 //表示图片透明度递减的速度

for(let i=0;i<items.length;i++){
const item = items[i] //获取每一张图片
const dis = Math.abs(i - index) //获取当前图片与中心图片的距离,并且取正数
const scale = scaleStep ** dis //计算图片需要缩放的比例 使用的是指数运算
const opacity = opacityStep ** dis //计算图片需要透明度的比例 使用的是指数运算
const sign = Math.sign(i - index) //判断图片是在中心图片的左边还是右边 sign的值返回的是-1或者1
const rotateY = i==index ? 0 : 30 * -sign //判断图片是在中心图片的左边还是右边,如果是中心图片则不旋转,否则旋转30度
let xoffset = (i - index) * xoffsetStep //计算图片的横向偏移量,每张图片之间是有一定距离的


//设置计算出来的样式
item.style.transform = `translateX(${xoffset}px) scale(${scale}) rotateY(${rotateY}deg)`
item.style.zIndex = items.length - dis
item.style.opacity = opacity
}
}

//最初先调用一下layout函数
layout()

//给prev和next按钮添加点击事件
prev.addEventListener("click", () => {
index--;
if(index < 0){
index = items.length - 1;
}
layout();
})

//给prev和next按钮添加点击事件
next.addEventListener("click", () => {
index++;
if(index > items.length - 1){
index = 0;
}
layout();
})

//给每一张图片添加点击事件
items.forEach((item, i) => {
item.addEventListener("click", () => {
index = i;
layout();
})
})
</script>

</html>