-
制作轮播图可以说是前端开发人员必须掌握的技能之一,可以很好的锻炼对js代码的熟悉和对dom结构的应用
-
这次的轮播图效果如下
一、制作思路
-
当一开始看到这种轮播图,我首先会去想成弄类名,然后设置上transform属性,然后配合skew实现弯曲轮播的效果,但是我发现图片的首尾会不相连
-
正确制作思路是把图片横向分为若干份,配合transform-delay是图片让人视觉差异的看起来像弯曲的
-
比如分成四等分
-
二、代码逻辑
2.1 html结构
-
代码
-
为什么要把li注释起来呢,因为后期会使用js动态生成
-
<ul class="box">
<!-- <li>
<div></div>
<div></div>
<div></div>
<div></div>
</li>
<li>
<div></div>
<div></div>
<div></div>
<div></div>
</li>
<li>
<div></div>
<div></div>
<div></div>
<div></div>
</li>
<li>
<div></div>
<div></div>
<div></div>
<div></div>
</li> -->
</ul>
2.2 css思路
-
我们的设计思路是把一张图片横向分为li份,然后在X轴方向(即侧面)可以看到一个正方形的结构,实质上是同一个li上的不同div设置了rotate属性
-
如果部分成若干份的话,每一个div是一张图片,就是我们熟悉的轮播图了
-
-
代码
-
注释了是因为会在js中添加
-
.box {
position: relative;
540px;
height: 200px;
margin: 100px auto;
li {
float: left;
height: 100%;
perspective: 50000px;
transform-style: preserve-3d;
transition: all 500ms ease;
> div {
position: absolute;
top: 0;
left: 0;
100%;
height: 100%;
background-size: 540px 200px;
// &:nth-child(1) {
// background-image: url('../../images/1.jpg');
// transform: translateZ(100px);
// }
// &:nth-child(2) {
// background-image: url('../../images/2.jpg');
// transform: rotateX(90deg) translateZ(100px);
// }
// &:nth-child(3) {
// background-image: url('../../images/3.jpg');
// transform: rotateX(180deg) translateZ(100px);
// }
// &:nth-child(4) {
// background-image: url('../../images/4.jpg');
// transform: rotateX(270deg) translateZ(100px);
// }
}
// &:nth-child(1) {
// left: 0;
// > div {
// background-position: 0 0;
// }
// }
// &:nth-child(2) {
// left: 135px;
// > div {
// background-position: -135px 0;
// }
// }
// &:nth-child(3) {
// left: 270px;
// > div {
// background-position: -270px 0;
// }
// }
// &:nth-child(4) {
// left: 405px;
// > div {
// background-position: -405px 0;
// }
// }
}
}
2.3 js思路
-
这里我们使用了jQuery代码库,方便了DOM的操作
(1)模拟动态数据
-
注意这里的img跟css的目录不一样,要根据js代码的位置写,我这里是写在html结构中的
// 数据
const path = '../images/'
const data = [
{ url: '1.jpg' },
{ url: '2.jpg' },
{ url: '3.jpg' },
{ url: '4.jpg' }
]
(2)定义参数
-
其中len是li的数量,delay是控制动画转速
-
max是预防连续点击出现的错误,这里设置可以储存两次点击,后面再点击事件里面会有体现
// 可变参数 len delay
const len = 30 // 总份数
const delay = 1.5// 延迟时间
let max = 2 // 最大累积数
const allWidth = $('.box').width()
const height = $('.box').height()
const partWidth = allWidth / len
// 旋转了的角度
let angle = 0
// 累积
let accumulation = 0
(3)创建DOM结构
for (let i = 0; i < len; i++) {
$('.box').append(function () {
let htmlArr = ['<li>']
for (let j = 0; j < data.length; j++) {
htmlArr.push('<div></div>')
}
htmlArr.push('</li>')
return $(htmlArr.join(''))
})
}
(4)为dom结构添加css
// 设置了统一的宽度
$('.box').children().width(partWidth).each(function (i1) {
// 这里设置了delay的事件,根据其横向是第几个li来设置的
$(this).css('transition-delay', `${delay * i1}ms`)
$(this).css({
// 这里设置了li的偏移量
left: `${i1 * partWidth}px`
// 下面为li的每一个div都设置了根据li的偏移量的背景图偏移量
}).children().css('background-position', `-${i1 * partWidth}px 0`).each(function (i2) {
$(this).css({
// 添加背景图再div上面,并且设置transform
'background-image': `url('${path + data[i2].url}')`,
transform: `rotateX(${90 * i2}deg) translateZ(${height / 2}px)`
})
})
})
(5)点击事件以及最大累积逻辑
$('.btn1').click(function () {
// 超过最大累积数量则return
if (accumulation >= max) {
return
// 大于0表示正在运动,但是没有超过最大累计数量可以增加累积数
} else if (accumulation > 0) {
accumulation++
return
}
// 调用运动函数
accumulation++
move()
})
// 判断accumulationd的递归
function move () {
angle += 90
// 每一次调用都会旋固定角度,每次角度都累加
$('.box').children().css({
transform: `rotateX(${angle}deg)`
})
// 累加器表示动画结束的时间,结束才减少累积数,如果还有累积则递归调用
setTimeout(function () {
accumulation--
if (accumulation) move()
}, 500 + (len - 1) * delay)
}
2.4 总js代码
$(function () {
// 数据
const path = '../images/'
const data = [
{ url: '1.jpg' },
{ url: '2.jpg' },
{ url: '3.jpg' },
{ url: '4.jpg' }
]
// 可变参数 len delay
const len = 30 // 总份数
const delay = 1.5// 延迟时间
let max = 2 // 最大累积数
const allWidth = $('.box').width()
const height = $('.box').height()
const partWidth = allWidth / len
// 旋转了的角度
let angle = 0
// 累积
let accumulation = 0
// 创建dom结构
for (let i = 0; i < len; i++) {
$('.box').append(function () {
let htmlArr = ['<li>']
for (let j = 0; j < data.length; j++) {
htmlArr.push('<div></div>')
}
htmlArr.push('</li>')
return $(htmlArr.join(''))
})
}
// 为dom结构增加css
$('.box').children().width(partWidth).each(function (i1) {
$(this).css('transition-delay', `${delay * i1}ms`)
$(this).css({
left: `${i1 * partWidth}px`
}).children().css('background-position', `-${i1 * partWidth}px 0`).each(function (i2) {
$(this).css({
'background-image': `url('${path + data[i2].url}')`,
transform: `rotateX(${90 * i2}deg) translateZ(${height / 2}px)`
})
})
})
// 点击事件
$('.btn1').click(function () {
if (accumulation >= max) {
return
} else if (accumulation > 0) {
accumulation++
return
}
accumulation++
move()
})
// 判断accumulationd的递归
function move () {
angle