思路
- 获取元素
- 设置鼠标图片区域时显示左右按钮
- 为了实现无缝滚动—克隆第一张图片的li放在最后
- 有几张轮播图就动态生成几个底部小圆圈
- 鼠标点击底部小按钮 点击的那个会变色
- 点击小圆点 跳转图片ul
- 点击右侧按钮,底部按钮跟右侧一起变化
- 绑定底部小按钮 跟随轮播图一起变化
- 轮播图片限定范围 限定右边 实现无缝滚动效果
- 轮播到第5张图的时候 底部按钮点亮第1个
- 快速点击 图片会快速轮播 需要节流阀限制快速轮播
- 自动播放轮播图
- 自动播放轮播图 鼠标经过 就停止
- 自动播放轮播图 鼠标移出 就开始
山海有灵艺术插画来自于站酷,文件已开源至GitHub
实现效果:
动画函数
function animate(obj, target, callback) {
// console.log(callback); callback = function() {} 调用的时候 callback()
// 先清除以前的定时器,只保留当前的一个定时器执行
clearInterval(obj.timer)
obj.timer = setInterval(function () {
// 步长值写到定时器的里面
// 把我们步长值改为整数 不要出现小数的问题
// var step = Math.ceil((target - obj.offsetLeft) / 10);
var step = (target - obj.offsetLeft) / 23
step = step > 0 ? Math.ceil(step) : Math.floor(step)
if (obj.offsetLeft == target) {
// 停止动画 本质是停止定时器
clearInterval(obj.timer)
// 回调函数写到定时器结束里面
// if (callback) {
// // 调用函数
// callback();
// }
callback && callback()
}
// 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px'
}, 5)
}
轮播图JS
window.onload = function () {
// # 1. 获取元素
let buttonL = document.querySelector('.iconl') //获取左按钮
let buttonR = document.querySelector('.iconr') //获取右按钮
let img_left = document.querySelector('.img-left') //获取整个左边区域
let viewpager = img_left.querySelector('.viewpager') //获取所有轮播图ul
let img = viewpager.querySelector('img') //获取每张轮播图
let B_button = document.querySelector('.bottom-button').querySelector('ul') //获取所有底部小按钮ul
let index = 0 //给index一个初始值
let imgwidth = img.offsetWidth //每张轮播图片的宽度
// # 2. 鼠标经过 就显示/隐藏左右按钮
//鼠标经过
img_left.addEventListener('mouseenter', function () {
buttonL.style.opacity = 1
buttonR.style.opacity = 1 //显示
// # 8.1 自动播放轮播图 优化:鼠标经过 就停止
clearInterval(time)
time = null // 清除定时器变量
})
//鼠标离开
img_left.addEventListener('mouseleave', function () {
buttonL.style.opacity = 0
buttonR.style.opacity = 0 //隐藏
// # 8.2 自动播放轮播图 优化:鼠标移出 就开始
time = setInterval(function () {
//手动调用点击事件1
buttonR.click()
}, 2000)
})
// # 3. 为了实现无缝滚动-克隆第一张图片的li放到最后
let clonefirst = viewpager.children[0].cloneNode(true) //深拷贝第一张轮播图
viewpager.appendChild(clonefirst) //向节点添加最后一个子节点
// # 4. 有几张轮播图就动态生成几个底部小圆圈
//遍历轮播图的ul
for (let i = 0; i < viewpager.children.length - 1; i++) {
let li = document.createElement('li') // 创建一个li
li.setAttribute('index', i) // 将li创建index属性并赋值
B_button.appendChild(li) // 把小li插入到ul里面
// # 5. 鼠标点击底部小按钮 点击的那个会变色
B_button.children[0].className = 'first' //给底部按钮的第一张图片样式
li.addEventListener('click', function () {
//遍历底部按钮ul 清空样式
for (let i = 0; i < B_button.children.length; i++) {
B_button.children[i].className = ''
}
//点击后 给样式
li.className = 'current'
// # 6. 点击小圆点 跳转图片ul
// ul的移动距离 = 小圆圈的索引号 * 图片的宽度
// let imgwidth = img.offsetWidth //每张轮播图片的宽度
index = this.getAttribute('index') //点击谁就得到当前的索引号
animate(viewpager, -index * imgwidth)
})
}
// # 7.4 优化3:快速点击 图片会快速轮播 需要节流阀限制快速轮播
let flag = true // 设置一个变量 flag 节流阀
// # 7. 点击右侧按钮,底部按钮跟右侧一起变化
buttonR.addEventListener('click', function () {
// # 7.2 优化1:轮播图片限定范围 限定右边 实现无缝滚动效果
if (flag) {
//点击一次后关闭
flag = false
index == viewpager.children.length - 1
? (viewpager.style.left = 0)
: index
index == viewpager.children.length - 1 ? (index = 0) : index
index++
//点击小按钮 让索引号自加
console.log(index)
console.log(-index * imgwidth)
animate(viewpager, -index * imgwidth, function () {
flag = true // 利用回调函数 动画执行完毕后 赋值为true,可以执行if里面的运算
})
// # 7.1 绑定底部小按钮 跟随轮播图一起变化
for (let i = 0; i < B_button.children.length; i++) {
B_button.children[i].className = ''
}
// # 7.3 优化2:轮播到第5张图的时候 底部按钮点亮第1个
let circle = index
circle == viewpager.children.length - 1 ? (circle = 0) : circle
B_button.children[circle].className = 'current'
}
})
buttonL.addEventListener('click', function () {
if (flag) {
flag = false
console.log(-index * imgwidth)
// index == 0 ? (viewpager.style.left = -4580 + 'px') : index
if (index == 0) {
index = viewpager.children.length - 1
viewpager.style.left = -index * imgwidth + 'px'
}
index == 0 ? (index = viewpager.children.length - 1) : index
index--
animate(viewpager, -index * imgwidth, function () {
flag = true
})
for (let i = 0; i < B_button.children.length; i++) {
B_button.children[i].className = ''
}
let circle = index
circle == viewpager.children.length - 1 ? (circle = 0) : circle
B_button.children[circle].className = 'current'
}
})
// # 8. 自动播放轮播图
let time = setInterval(function () {
//手动调用点击事件
buttonR.click()
}, 2500)
}
HTML部分
<!DOCTYPE html>
<html lang="en">
<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>轮播图</title>
<link rel="stylesheet" href="./css/base.css" />
<link rel="stylesheet" href="./iconfont/iconfont.css" />
<link rel="stylesheet" href="./css/viewpager.css" />
<script src="./js/animate.js"></script>
<script src="./js/index.js"></script>
</head>
<!-- !!添加效果点击更换背景 -->
<body>
<div class="bigbox w">
<!-- !!左边轮播图 -->
<div class="img-left">
<ul class="viewpager">
<li>
<a href="#">
<img src="./img/《山海有灵》合集_XISION-站酷ZCOOL_1.jpg" alt=""
/></a>
</li>
<li>
<a href="#">
<img src="./img/《山海有灵》合集_XISION-站酷ZCOOL_2.jpg" alt=""
/></a>
</li>
<li>
<a href="#">
<img src="./img/《山海有灵》合集_XISION-站酷ZCOOL_3.jpg" alt=""
/></a>
</li>
<li>
<a href="#">
<img src="./img/《山海有灵》合集_XISION-站酷ZCOOL_4.jpg" alt=""
/></a>
</li>
<li>
<a href="#">
<img src="./img/《山海有灵》合集_XISION-站酷ZCOOL_5.jpg" alt=""
/></a>
</li>
</ul>
<!-- #左右按钮 -->
<div class="left-right-button">
<a href="javascript:;">
<i class="iconfont icon-xialajiantouxiao iconl"></i
></a>
<a href="javascript:;">
<i class="iconfont icon-xialajiantouxiao iconr"></i>
</a>
</div>
<!-- #底部按钮 -->
<div class="bottom-button">
<ul>
<!-- <li></li>
<li></li>
<li></li>
<li></li>
<li></li> -->
</ul>
</div>
</div>
<!-- !!右边文字 -->
<div class="text-right">
<h3>山海有灵</h3>
<p class="world">
“晴对雨,地对天,天地对山川”<br />
今年,他的毕业设计在网络刷屏<br />
龙、梯田与劳动人民的交错令人赞叹不已<br />
凝视着画中独具神韵的青龙<br />
耳边仿佛响起了远古的龙吟<br />
"龙作为画面主题不但为画面的故事增添了更多神秘色彩<br />
也增添了画面的视觉冲击力<br />
在中国文化中,龙有着呼风唤雨的本事<br />
龙的出现则代表了耕耘丰收<br />
所以整套作品是对中国农耕文化的致敬与再活化。"<br />
</p>
<p class="writer">——xision</p>
</div>
</div>
</body>
</html>
less部分
.w {
margin: 220px auto;
width: 1360px;
}
body {
.icon-jiantoushang {
color: aliceblue;
}
background-color: rgb(26, 26, 26);
.bigbox {
background-color: rgb(83, 83, 83);
display: flex;
align-items: center;
justify-content: space-between;
height: 380px;
box-shadow: 1px 1px 6px rgba(255, 255, 255, 0.3);
// 左边轮播图
.img-left {
position: relative;
left: 10px;
width: 916px;
height: 360px;
overflow: hidden;
.viewpager {
position: absolute;
top: 0;
left: 0;
display: flex;
img {
width: 916px;
height: 360px;
}
}
// #左右按钮
.left-right-button {
.iconl {
position: absolute;
bottom: 156px;
left: 5px;
font-size: 30px;
color: white;
transform: rotate(90deg);
}
.iconr {
position: absolute;
bottom: 156px;
right: 5px;
font-size: 30px;
color: white;
transform: rotate(-90deg);
}
.icon-xialajiantouxiao:active {
color: rgb(155, 217, 255);
}
.iconfont {
cursor: pointer;
transition: all 0.3s;
}
}
// #底部按钮
.bottom-button {
ul {
position: absolute;
width: 150px;
height: 20px;
// background-color: antiquewhite;
bottom: 0px;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
justify-content: space-around;
align-items: center;
li {
width: 12px;
height: 12px;
cursor: pointer;
border-radius: 50%;
background-color: #fff;
outline: 1.5px solid #2980b9;
}
.first {
width: 12px;
height: 12px;
cursor: pointer;
border-radius: 50%;
background-color: #a9e8ff;
outline: 1.5px solid #2980b9;
}
.current {
width: 12px;
height: 12px;
cursor: pointer;
border-radius: 50%;
background-color: #a9e8ff;
outline: 1.5px solid #2980b9;
}
}
}
}
}
//右边文字
.text-right {
display: flex;
flex-direction: column;
justify-content: center;
h3 {
padding-bottom: 10px;
margin-left: 6px;
color: white;
font-size: 26px;
// 字间距
letter-spacing: 15px;
}
p {
width: 370px;
color: rgb(233, 233, 233);
}
.world {
margin-top: 12px;
line-height: 25px;
font-size: 13px;
}
.writer {
text-align: right;
margin-top: 10px;
padding-right: 25px;
width: 340px;
}
}
}