JS案例-网页轮播图
- 鼠标经过轮播图模块,左右按钮提示,离开隐藏左右按钮
- 点击右侧按钮一次,图片往左播放一张,以此类推,左侧按钮同理
- 图片播放的同时,下面小圆圈模块跟随一起变化
- 点击小圆圈,可以播放相应图片
- 鼠标不经过轮播图,轮播图也会自动播放图片
- 鼠标经过,轮播图模块自动播放停止
第一步 鼠标经过显示按钮 鼠标离开按钮消失
//获取元素
var arrow_l = document.querySelector('.arrow-l');
var arrow_r = document.querySelector('.arrow-r');
var focus = document.querySelector('.focus');
//鼠标经过显示按钮
focus.addEventListener('mouseenter', function () {
arrow_l.style.display = 'block';
arrow_r.style.display = 'block';
})
focus.addEventListener('mouseleave', function () {
arrow_l.style.display = 'none';
arrow_r.style.display = 'none';
})
第二步:考虑如何动态生成小圆圈 让小圆圈个数与图片个数一致
首先得到ul里图片个数,利用循环动态生成小圆圈,创建节点并插入节点,然后给第一个小圆圈插入current类
//动态生成小圆圈
var ul = focus.querySelector('ul');//必须限定focus里面的
var ol = focus.querySelector('.circle');
for (var i = 0; i < ul.children.length; i++) {
var li = document.createElement('li');
ol.appendChild(li);
//[]
}
ol.children[0].className = 'current';//第一个小圆圈默认变色
第三步:利用排他思想,实现点击小圆圈变色
//可以直接在生成小圆圈的同时绑定点击事件
li.addEventListener('click', function () {
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = '';
}
this.className = 'current';
})
第四步:点击小圆圈滚动图片
注意是ul在移动
当点击某个小圆圈,就让图片滚动,移动距离为图片索引号*图片宽度
知识点:索引号如何得到?
- 通过给每个li设定自定义属性点击时获取自定义属性
var ul = focus.querySelector('ul');//必须限定focus里面的
var ol = focus.querySelector('.circle');
for (var i = 0; i < ul.children.length; i++) {
var li = document.createElement('li');
//通过自定义属性记录小圆圈索引号
li.setAttribute('index', i);
ol.appendChild(li);
//可以直接在生成小圆圈的同时绑定点击事件
li.addEventListener('click', function () {
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = '';
}
this.className = 'current';
//点击小圆圈移动图片
var index = this.getAttribute('index');
var focusWidth = focus.offsetWidth;
animate(ul, -index * focusWidth);
})
}
第五步:点击左右按钮滚动
思路:声明一个变量,每点击一次number++
但是当点击次数过多会走到空白区域
如何实现无缝滚动?
- 把ul第一个li复制一份,放到ul后面,当图片滚动到克隆的最后一张的时候不做动画直接快速跳回第一张:left=0,同时num=0;
如何克隆第一张图片?
- 利用节点的克隆和添加操作
ol.children[0].className = 'current';//第一个小圆圈默认变色
var firstLi = ul.children[0].cloneNode(true);
ul.appendChild(firstLi);//克隆第一张图
var num = 0;
arrow_r.addEventListener('click', function () {
if (num == ul.children.length - 1) {
ul.style.left = 0;
num = 0;
}
num++;
animate(ul, -num * focusWidth);
})
第六步:点击按钮小圆圈跟随变化
再定义一个变量circle,每次点击一次按钮则++,如果circle==4,说明走到最后这张图片,使circle复原
var circle = 0;
arrow_r.addEventListener('click', function () {
if (num == ul.children.length - 1) {
ul.style.left = 0;
num = 0;
}
num++;
animate(ul, -num * focusWidth);
//实现点击按钮小圆圈跟随变化
circle++;
if (circle == ol.children.length) {
circle = 0;
}
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = '';
}
ol.children[circle].className = 'current';
第七步:此时有两个bug
按钮的点击操作和圆点的点击是不同变量,无法共同使用,两个事件的变量需要同步
应该在点击小圆点事件中添加
num = index;
circle = index;
第八步:左侧按钮同理
arrow_l.addEventListener('click', function () {
if (num == 0) {
num = ul.children.length - 1;
ul.style.left = -num * focusWidth + 'px';
}
num--;
animate(ul, -num * focusWidth);
//实现点击按钮小圆圈跟随变化
circle--;
if (circle < 0) {
circle = ol.children.length - 1;
}
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = '';
}
ol.children[circle].className = 'current';
})
第十步 代码优化 相同的可以封装函数
function circleChange() {
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = '';
}
ol.children[circle].className = 'current';
}
三元表达式简化
circle = circle < 0 ? ol.children.length - 1 : circle;
// if (circle < 0) {
// circle = ol.children.length - 1;
// }
最后:自动播放!
发现自动播放时和点击右侧按钮很类似
可以手动调用右侧按钮点击事件arrow_r.click()
focus.addEventListener('mouseenter', function () {
arrow_l.style.display = 'block';
arrow_r.style.display = 'block';
clearInterval(timer);//鼠标经过停止定时器
timer = none;
})
focus.addEventListener('mouseleave', function () {
arrow_l.style.display = 'none';
arrow_r.style.display = 'none';
timer = setInterval(function () {//鼠标离开开启定时器
arrow_r.click();//手动调用点击事件
}, 2000)
})
补充:节流阀
防止轮播图按钮连续点击造成播放过快
目的:当上一个函数动画执行完毕,再去执行下一个函数动画,让事件无法连续触发
利用回调函数,添加一个变量来控制,锁住函数和解锁函数
- 开始设置一个变量var flag=true
- if(flag) {flag=false;do something}关闭水龙头
利用回调函数 动画执行完毕(使用回调函数),false=true 打开水龙头
完整js代码
window.addEventListener('load', function () {
//获取元素
var arrow_l = document.querySelector('.arrow-l');
var arrow_r = document.querySelector('.arrow-r');
var focus = document.querySelector('.focus');
var focusWidth = focus.offsetWidth;
var num = 0;
//鼠标经过显示按钮
focus.addEventListener('mouseenter', function () {
arrow_l.style.display = 'block';
arrow_r.style.display = 'block';
clearInterval(timer);//鼠标经过停止定时器
timer = none;
})
focus.addEventListener('mouseleave', function () {
arrow_l.style.display = 'none';
arrow_r.style.display = 'none';
timer = setInterval(function () {//鼠标离开开启定时器
arrow_r.click();//手动调用点击事件
}, 2000)
})
//动态生成小圆圈
var ul = focus.querySelector('ul');//必须限定focus里面的
var ol = focus.querySelector('.circle');
for (var i = 0; i < ul.children.length; i++) {
var li = document.createElement('li');
//通过自定义属性记录小圆圈索引号
li.setAttribute('index', i);
ol.appendChild(li);
//可以直接在生成小圆圈的同时绑定点击事件
li.addEventListener('click', function () {
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = '';
}
this.className = 'current';
//点击小圆圈移动图片
var index = this.getAttribute('index');
//当我们点击了某个li,就要把这个li的索引号给num//////////////////////////////bug必须改
num = index;
circle = index;
animate(ul, -index * focusWidth);
})
}
ol.children[0].className = 'current';//第一个小圆圈默认变色
var firstLi = ul.children[0].cloneNode(true);
ul.appendChild(firstLi);//克隆第一张图
var circle = 0;//全局变量
var flag = true;
arrow_r.addEventListener('click', function () {
if (flag) {
flag = false;//关闭节流阀
if (num == ul.children.length - 1) {
ul.style.left = 0;
num = 0;
}
num++;
animate(ul, -num * focusWidth, function () {
flag = true;//打开节流阀
});
//实现点击按钮小圆圈跟随变化
circle++;
if (circle == ol.children.length) {
circle = 0;
}
circleChange();
}
})
arrow_l.addEventListener('click', function () {
if (flag) {
flag = false;
if (num == 0) {
num = ul.children.length - 1;
ul.style.left = -num * focusWidth + 'px';
}
num--;
animate(ul, -num * focusWidth, function () {
flag = true;
});
//实现点击按钮小圆圈跟随变化
circle--;
circle = circle < 0 ? ol.children.length - 1 : circle;
// if (circle < 0) {
// circle = ol.children.length - 1;
// }
circleChange();
}
})
function circleChange() {
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = '';
}
ol.children[circle].className = 'current';
}
var timer = setInterval(function () {
arrow_r.click();//手动调用点击事件
}, 2000)
})
animate.js
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) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (obj.offsetLeft == target) {
// 停止动画 本质是停止定时器
clearInterval(obj.timer);
// 回调函数写到定时器结束里面
// if (callback) {
// // 调用函数
// callback();
// }
callback && callback();//借助短路运算如果有参数传入才会调用callback
}
// 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
相关html
<div class="focus">
<a href="javascript:;" class="arrow-l"><</a>
<a href="javascript:;" class="arrow-r">></a>
<ul>
<li><a href="#"><img src="upload/focus1.png" alt=""></a></li>
<li><a href="#"><img src="upload/focus1.jpg" alt=""></a></li>
<li><a href="#"><img src="upload/focus2.jpg" alt=""></a></li>
<li><a href="#"><img src="upload/focus3.jpg" alt=""></a></li>
</ul>
<ol class="circle">
</ol>
相关css
.focus {
float: left;
overflow: hidden;
position: relative;
width: 721px;
height: 455px;
}
.arrow-l,.arrow-r {
display: none;
position: absolute;
top: 50%;
margin-top: -20px;
width: 24px;
height: 40px;
color:rgb(175, 170, 170);
font-size: 20px;
line-height: 40px;
text-align: center;
z-index: 10;
background:rgba(0,0,0, .5);
}
.arrow-l {
left: 0;
border-radius: 0 30px 30px 0;
}
.arrow-r {
right: 0;
border-radius: 30px 0 0 30px;
}
.focus ul{
position: absolute;
top: 0;
left: 0;
width: 600%;
}
.focus ul li{
float: left;
}
.circle{
position: absolute;
bottom: 0;
left: 40px;
bottom: 0;
height: 18px;
width: 150px;
}
.circle li{
height: 12px;
width: 12px;
float: left;
border-radius: 8px;
border: 1px solid #e4e4e4;
margin: 0 4px;
}
.current {
background-color: #e4e4e4;
}
分类:
前端
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!