实现思路
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D版轮播</title>
<!-- IMPORT CSS -->
<link rel="stylesheet" href="css/reset.min.css">
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<header class="headerBox">
<div class="container" id="container">
<!-- 轮播图 -->
<div class="wrapper">
<!-- <div class="slide active">
<img src="images/01.jpg" alt="">
<div class="mark"></div>
<div class="desc">
<p>蒙奇·D·路飞</p>
<p>身份:草帽海贼团船长</p>
<p>梦想:找到ONE PIECE,并成为海贼王</p>
</div>
</div> -->
</div>
<!-- 导航安钮 -->
<div class="navigation prev"></div>
<div class="navigation next"></div>
</div>
</header>
<!-- IMPORT JS -->
<script src="js/index.js" defer></script>
</body>
</html>
CSS
.headerBox{
height: 350px;
background: url('../images/bg.jpg') no-repeat;
background-size: cover;
position: relative;
}
.container{
position:absolute;
top:50%;
left: 50%;
transform: translate(-50%,-50%);
width:1100px;
height:300px;
}
.container .wrapper{
position: relative;
height: 100%;
}
.container .wrapper .slide{
position:absolute;
top:50%;
left: 50%;
transform: translate(-50%,-50%);
z-index: 0;
box-sizing: border-box;
width: 25%;
height: 100%;
border: 3px solid #000;
overflow: hidden;
/* 以后修改slide样式,执行css3过渡动画 */
transition: transform 0.5s;
cursor: pointer;
}
.container .wrapper .slide img{
display: block;
width: 100%;
height: 100%;
}
.container .wrapper .slide .mark{
position: absolute;
top:0;
left:0;
width: 100%;
height: 100%;
background: rgba(0,0,0,.75);
transition: background .5s;
}
.container .wrapper .slide.active .mark,
.container .wrapper .slide:hover .mark{
background: rgba(0,0,0,0);
}
.container .wrapper .slide .desc{
position: absolute;
left:0;
bottom: 0;
box-sizing: border-box;
padding: 10px;
width: 100%;
height: 40%;
background: rgba(0,0,0,.75);
/* 渐变 */
background: -webkit-linear-gradient(top,rgba(0,0,0,.35),rgba(0,0,0,.75));
/* 开始不显示 */
transform:translateY(100%);
transition:transform .3s;
overflow: hidden;
}
.container .wrapper .slide.active:hover .desc{
transform:translateY(0);
}
.container .wrapper .slide .desc p{
line-height: 2;
color:#fff;
font-size: 12px;
}
/* 按钮 */
.container .navigation{
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 39px;
height: 80px;
background: url('../images/btn.png') no-repeat;
display: none;
cursor: pointer;
}
.container .navigation.prev{
left:0;
background-position: 0 0;
}
.container .navigation.next{
right:0;
background-position: -39px 0;
}
JS
(function () {
// 获取元素
let container = document.querySelector('#container'), //最外层轮播图容器
wrapper = container.querySelector('.wrapper'),//包裹所有图片的容器
slides = null,//所有图片的集合
navprev = container.querySelector('.navigation.prev'),//点击上一个
navnext = container.querySelector('.navigation.next'); //点击下一个
let step = 0, //当前显示
atuoTimer = null,//存放定时器
count = 0,//一共多少个
interval = 1000,//定时器的时间
data = [];//存放的数据
// 获取数据
const queryData = function queryData() {
let xhr = new XMLHttpRequest();
xhr.open('GET', './data.json', false);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
data = JSON.parse(xhr.responseText);
}
};
xhr.send();
};
// 实现数据绑定
//initial 初始值
const binding = function binding(initial) {
//1.如果数据不足5条,我们需要补齐5条
if (data.length === 0) return;
while (data.length < 5) {
let diff = 5 - data.length,
clone = data.slice(0, diff);
data = data.concat(clone);
}
count = data.length;
// 2.在绑定slide之前 需要按照规则给每个slide设置的样式 增加到数据的每一项中[z-index,className,sty{transform}]
let temp1 = step - 2,
temp2 = step - 1,
temp3 = step, //正中间的那个
temp4 = step + 1,
temp5 = step + 2;
if (temp1 < 0) temp1 = count + temp1;
if (temp2 < 0) temp2 = count + temp2;
if (temp4 > count - 1) temp4 = temp4 - count;
if (temp5 > count - 1) temp5 = temp5 - count;
data = data.map((item, index) => {
let zIndex = 0,
className = 'slide',
transform = 'translate(-50%,-50%) scale(0.55)';
switch (index) {
case temp1:
zIndex = 1;
transform = 'translate(-195%,-50%) scale(0.7)';
break;
case temp2:
zIndex = 2;
transform = 'translate(-130%,-50%) scale(0.85)';
break;
case temp3:
className = 'slide active',
zIndex = 3;
transform = 'translate(-50%,-50%) scale(1)';
break;
case temp4:
zIndex = 2;
transform = 'translate(30%,-50%) scale(0.85)';
break;
case temp5:
zIndex = 1;
transform = 'translate(95%,-50%) scale(0.7)';
break;
}
item.className = className;
item.sty = `z-index:${zIndex};transform:${transform};`;
return item;
});
//5.如果initial不是true,说明不是第一次执行这个方法,此时我们按照最新计算的样式,修改每个slide样式即可
if (!initial) {
data.forEach((item, index) => {
let {
className,
sty
} = item;
slides[index].className = className;
slides[index].style.cssText = sty;//cssText
})
return;
}
//3.数据渲染,动态创建slide 并且设置样式
let str = ``;
data.forEach(item => {
let { pic, className, sty, descript: { name, identity, dream } } = item;
str += `<div class="${className}" style="${sty}">
<img src="${pic}" alt="">
<div class="mark"></div>
<div class="desc">
<p>${name}</p>
<p>身份:${identity}</p>
<p>梦想:${dream}</p>
</div>
</div> `;
});
wrapper.innerHTML = str;
//4.获取slide&控制按钮显示
slides = wrapper.querySelectorAll('.slide'),
navprev.style.display = navnext.style.display = 'block';
};
// 自动轮播
const autoMove = function autoMove() {
step++;
if (step >= count) step = 0;
binding();
};
// 控制自行轮播暂停或者开启
container.addEventListener('mouseenter', () => clearInterval(atuoTimer))
container.addEventListener('mouseleave', () => atuoTimer = setInterval(autoMove, interval));
// 点击左右按钮切换
container.addEventListener('click', function (ev) {
let target = ev.target,
targetTag = target.tagName,
targetClass = target.className;
if (targetTag === 'DIV' && targetClass.includes('navigation')) {
if (targetClass.includes('prev')) {
// 点击的是左按钮
step--;
if (step < 0) step = count - 1;
binding();
return;
}
//右按钮和自动轮播一样
autoMove();
};
});
queryData();
binding(true);//绑定数据
atuoTimer = setInterval(autoMove, interval); //设置轮循定时器
})();
JSON
[{
"id": 1,
"pic": "images/01.jpg",
"descript": {
"name": "蒙奇·D·路飞",
"identity": "草帽海贼团船长",
"dream": "找到ONE PIECE,并成为海贼王"
}
}, {
"id": 2,
"pic": "images/02.jpg",
"descript": {
"name": "罗罗诺亚·索隆",
"identity": "草帽海贼团战斗员",
"dream": "世界第一大剑豪"
}
}, {
"id": 3,
"pic": "images/03.jpg",
"descript": {
"name": "“小贼猫”娜美",
"identity": "草帽海贼团航海士",
"dream": "绘制出自己的世界地图、绘制全世界的航海图"
}
}, {
"id": 4,
"pic": "images/04.jpg",
"descript": {
"name": "“GOD”▪乌索普",
"identity": "草帽海贼团狙击手",
"dream": "成为勇敢的海上战士"
}
}, {
"id": 5,
"pic": "images/05.jpg",
"descript": {
"name": "“黑足”山治",
"identity": "草帽海贼团厨师",
"dream": "寻找传说中的奇迹之海-ALL BLUE"
}
}, {
"id": 6,
"pic": "images/06.jpg",
"descript": {
"name": "托尼托尼·乔巴",
"identity": "草帽海贼团船医",
"dream": "成为万能药"
}
}, {
"id": 7,
"pic": "images/07.jpg",
"descript": {
"name": "“改造人”弗兰奇",
"identity": "草帽海贼团船工",
"dream": "制造出梦想之船"
}
}, {
"id": 8,
"pic": "images/08.jpg",
"descript": {
"name": "“鼻歌”&“灵魂之王”布鲁克",
"identity": "草帽海贼团音乐家",
"dream": "环绕世界一周到伟大航道双子岬跟伙伴鲸鱼“拉布”重逢"
}
}, {
"id": 9,
"pic": "images/09.jpg",
"descript": {
"name": "“恶魔之子”妮可·罗宾",
"identity": "草帽海贼团考古学家",
"dream": "在历史正文碑的指引下,到达伟大航道的尽头“拉夫德鲁”"
}
}]