轮播图也称为焦点图,是网页中比较常见的网页特效。
因为html和css阶段看的尚硅谷课程,所以采用课程中的小米商城项目,在项目搭建的过程中遇到一个经典问题
<div class="banner-wrap">
<div class="banner w">
<ul class="img-list clearfix">
<li><a href="#"><img src="./img/banner2.png" alt="">a>li>
<li><a href="#"><img src="./img/banner3.png" alt="">a>li>
<li><a href="#"><img src="./img/banner1.png" alt="">a>li>
ul>
<div class="pointer">
<a class="active" href="#">a>
<a href="#">a>
<a href="#">a>
div>
<div class="prev-next">
<a class="prev" href="#">a>
<a class="next" href="#">a>
div>
div>
div>
最初的css代码:
.banner{
position: relative;
height: 460px;
}
.banner .img-list{
/* 因为有三张图片,所有设置吧ul宽度设置为banner的3倍 */
width: 300%;
}
/* 让banner中的li图片横向排列 */
.banner .img-list li{
float: left;
}
/* 设置轮播图 */
.banner img{
width: 100%;
vertical-align: top;
}
:
问题1:img和li宽度均变为图片本身的宽度,而非最初的banner宽度
问题分析::因为img中的wdith设置为100%,宽度由banner继承而来,而当li设置向左浮动时,img无处继承,li也被img撑开,所以宽度均变为图片本身的宽度
解决方法:为img设置宽度
,此处设置为1226px;
问题2:修改后li的位置仍为发生改变
问题分析:为元素开启了向左浮动且前边没有其他浮动元素,所以应该向左浮动且不会从父元素中移出;没有发生改变的原因是因为li浮动开启BFC时,父元素img-list高度塌陷
而绝对定位也移出,所以位置异常
解决方法:为img-list添加clearfix
类
(链接:高度塌陷和外边距重叠原理及解决方案)
html改动处代码:
<ul class="img-list clearfix">
<li><a href="#"><img src="./img/banner2.png" alt="">a>li>
<li><a href="#"><img src="./img/banner3.png" alt="">a>li>
<li><a href="#"><img src="./img/banner1.png" alt="">a>li>
ul>
css修改后代码:
.banner .img-list{
width: 400%;
}
/* 让banner中的li图片横向排列 */
.banner .img-list li{
float: left;
}
/* 设置轮播图 */
.banner img{
width: 1226px;
vertical-align: top;
}
animate.js要放在index.js上边引入
添加load事件
,页面加载完毕再调用js轮播图也称为焦点图,是网页中比较常见的网页特效。
功能需求:
以下的所有JS代码中若有不知道的class名,可返回上方查看html结构
JS代码:
window.addEventListener('load', function(){
// 获取元素
var prev = document.querySelector('.prev');
var next = document.querySelector('.next');
var banner = document.querySelector('.banner');
var bannerWidth = banner.offsetWidth;
// 鼠标经过banner显示隐藏左右按钮
banner.addEventListener('mouseenter', function(){
prev.style.display = 'block';
next.style.display = 'block';
})
banner.addEventListener('mouseleave', function(){
prev.style.display = 'none';
next.style.display = 'none';
})
核心思路:小圆点的个数要与banner图片张数一致:有几张图 就生成几个小圆圈
首先获取 ul中包裹图片的li数量:有多少张图,就有多少li
以li的数量循环动态创建小圆圈: createElement(‘a’)
将生成的a(小圆圈)添加到 pointer中 :pointer.appendChild(a);
为第一个小圆圈需要添加 current 类
var ul = banner.querySelector('ul');
var pointer = document.querySelector('.pointer');
for(var i =0; i<ul.children.length; i++){
pointer.appendChild(a);
}
// 把pointer里面的第一个a设置类名为current
pointer.children[0].className = 'current';
//生成每一个a小圆圈同时添加点击事件
a.addEventListener('click', function(){
// (排他思想使小圆圈唯一current类名)
// 清除每一个小圆圈的current类名
for(var i = 0; i<ul.children.length-1; i++){//此处减一的原因要深究:异步
pointer.children[i].className = '';
}
// 只留下点击的小圆圈 current样式
this.className = 'current';
css代码:
.banner .img-list{
width: 500%;
position: absolute;
top: 0;
left: 0;
}
JS代码:
// 3.动态生成小圆圈,有几张图 就生成几个小圆圈
var ul = banner.querySelector('ul');
var pointer = document.querySelector('.pointer');
for(var i =0; i<ul.children.length; i++){
// 创建小圆圈
var a = document.createElement('a');
// 记录当前小圆圈的索引号 通过自定义属性来做
a.setAttribute('index',i);
// 添加小圆圈
pointer.appendChild(a);
//
// 4.生成每一个a小圆圈同时添加点击事件
a.addEventListener('click', function(){
// (排他思想使小圆圈唯一current类名)
// 清除每一个小圆圈的current类名
for(var i = 0; i<ul.children.length-1; i++){//此处减一的原因要深究:异步
pointer.children[i].className = '';
}
// 只留下点击的小圆圈 current样式
this.className = 'current';
// 5.点击小圆圈,移动图片,移动的是ul(img-list)
// ul的移动距离就是小圆圈的索引号 乘以 图片的宽度(负值)
// 当我们点击了哪个小圆圈a,就获得它的索引号
var index = this.getAttribute('index');
animate(ul, - index*bannerWidth);
点击一次,滚动一张图片;点击按钮时,小圆圈也随着变化
// 6.克隆第一张图片(li)放到ul最后面
var first = ul.children[0].cloneNode(true);
ul.appendChild(first);
// 7.点击右侧按钮,图片滚动一张
var num = 0;
// circle控制小圆圈的播放
var circle = 0;
next.addEventListener('click', function(){
//无缝滚动原理:复制第一张图片放到最后;判断如果走到最后一张图,则ul的left复原为0
if(num == ul.children.length -1){
ul.style.left = 0;
num = 0;
}
num++;
animate(ul, - num*bannerWidth)
// 8.点击右侧按钮,小圆圈也跟随变化,可以在声明一个变量circle
circle++;
// 如果circle =3,就说明走到最后一张图片了(克隆的那张)我们就复原
if(circle == pointer.children.length){
circle =0;
}
// 调用函数
circleChange();
}
})
// 9.左侧按钮设置
prev.addEventListener('click', function(){
//无缝滚动原理:复制第一张图片放到最后;判断如果走到最后一张图,则ul的left复原为0
if(num == 0){
num = ul.children.length-1;
ul.style.left = - num*bannerWidth + 'px';
}
num--;
animate(ul, - num*bannerWidth)
// 点击左侧按钮,小圆圈也跟随变化,可以声明一个变量circle
circle--;
// 如果circle小于0,说明小圆圈选中状态跳到最后一张上
if(circle < 0){
circle =pointer.children.length-1;
}
circleChange();
}
})
//将小圆圈排他封装成函数
function circleChange(){
// 先清除其他小圆圈的样式
for(var i = 0; i<pointer.children.length; i++){
pointer.children[i].className = '';
}
// 留下当前小圆圈的current
pointer.children[circle].className = 'current';
}
bug:点击左右侧按钮和小圆圈均可实现对应的功能;但若先点击小圆圈(如点最后一个),再点击右侧按钮,此时会发现跳转到了第二张图片而不是第一张,这是因为按钮滚动图片时是用num值控制,而点击小圆圈为对其造成影响
;同理小圆点也有异常情况
解决方法:在点击小圆圈时,把索引号赋值给num和circle
// 5.点击小圆圈,移动图片,移动的是ul(img-list)
// ul的移动距离就是小圆圈的索引号 乘以 图片的宽度(负值)
// 当我们点击了哪个小圆圈a,就获得它的索引号
var index = this.getAttribute('index');
animate(ul, - index*bannerWidth);
// 点击小圆圈后,把小圆圈索引号赋值给num:右侧按钮通过num控制图片移动
num = index;//不加此代码:通过小圆点跳到最后一张图,点击右侧按钮 发现跳到第二张图,因为点击时num没发生改变,而箭头通过num控制
// 点击小圆圈后,把小圆圈索引号赋值给circle:circle控制小圆圈的样式
circle = index;
添加定时器
// 10.自动播放轮播图
var timer = setInterval(function(){
// 手动调用事件
next.click();
},3000)
思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数。
开始设置一个变量:var flag = true; if(flag) {flag = false; do something}:关闭水龙头
利用回调函数动画执行完毕:flag = true 打开水龙头
window.addEventListener('load', function(){
// 1.获取元素
var prev = document.querySelector('.prev');
var next = document.querySelector('.next');
var banner = document.querySelector('.banner');
var bannerWidth = banner.offsetWidth;
// 2.鼠标经过banner显示隐藏左右按钮
banner.addEventListener('mouseenter', function(){
prev.style.display = 'block';
next.style.display = 'block';
clearInterval(timer);
timer = null;//清除定时器变量
})
banner.addEventListener('mouseleave', function(){
prev.style.display = 'none';
next.style.display = 'none';
timer = setInterval(function(){
// 手动调用事件
next.click();
},3000)
})
// 3.动态生成小圆圈,有几张图 就生成几个小圆圈
var ul = banner.querySelector('ul');
var pointer = document.querySelector('.pointer');
for(var i =0; i<ul.children.length; i++){
// 创建小圆圈
var a = document.createElement('a');
// 记录当前小圆圈的索引号 通过自定义属性来做
a.setAttribute('index',i);
// 添加小圆圈
pointer.appendChild(a);
//
// 4.生成每一个a小圆圈同时添加点击事件
a.addEventListener('click', function(){
// (排他思想使小圆圈唯一current类名)
// 清除每一个小圆圈的current类名
for(var i = 0; i<ul.children.length-1; i++){//此处减一的原因要深究:异步
pointer.children[i].className = '';
}
// 只留下点击的小圆圈 current样式
this.className = 'current';
// 5.点击小圆圈,移动图片,移动的是ul(img-list)
// ul的移动距离就是小圆圈的索引号 乘以 图片的宽度(负值)
// 当我们点击了哪个小圆圈a,就获得它的索引号
var index = this.getAttribute('index');
animate(ul, - index*bannerWidth);
// 点击小圆圈后,把小圆圈索引号赋值给num:右侧按钮通过num控制图片移动
num = index;//不加此代码:通过小圆点跳到最后一张图,点击右侧按钮 发现跳到第二张图,因为点击时num没发生改变,而箭头通过num控制
// 点击小圆圈后,把小圆圈索引号赋值给circle:circle控制小圆圈的样式
circle = index;
})
}
// 把pointer里面的第一个a设置类名为current
pointer.children[0].className = 'current';
// 6.克隆第一张图片(li)放到ul最后面
var first = ul.children[0].cloneNode(true);
ul.appendChild(first);
// 7.点击右侧按钮,图片滚动一张
var num = 0;
// circle控制小圆圈的播放
var circle = 0;
// 节流阀
var flag = true;
next.addEventListener('click', function(){
if (flag){
flag =false;//关闭节流阀
//无缝滚动原理:复制第一张图片放到最后;判断如果走到最后一张图,则ul的left复原为0
if(num == ul.children.length -1){
ul.style.left = 0;
num = 0;
}
num++;
animate(ul, - num*bannerWidth, function(){
flag = true;//打开节流阀
});
// 8.点击右侧按钮,小圆圈也跟随变化,可以在声明一个变量circle
circle++;
// 如果circle =3,就说明走到最后一张图片了(克隆的那张)我们就复原
// if(circle == pointer.children.length){
// circle =0;
// }
// 优化:
circle = circle == pointer.children.length? 0 :circle;
// 调用函数
circleChange();
}
})
// 9.左侧按钮设置
prev.addEventListener('click', function(){
if(flag){
flag = false;
//无缝滚动原理:复制第一张图片放到最后;判断如果走到最后一张图,则ul的left复原为0
if(num == 0){
num = ul.children.length-1;
ul.style.left = - num*bannerWidth + 'px';
}
num--;
animate(ul, - num*bannerWidth, function(){
flag = true;
});
// 点击左侧按钮,小圆圈也跟随变化,可以声明一个变量circle
circle--;
// 如果circle小于0,说明小圆圈选中状态跳到最后一张上
// if(circle < 0){
// circle =pointer.children.length-1;
// }
circle = circle<0? pointer.children.length-1 : circle;
circleChange();
}
})
function circleChange(){
// 先清除其他小圆圈的样式
for(var i = 0; i<pointer.children.length; i++){
pointer.children[i].className = '';
}
// 留下当前小圆圈的current
pointer.children[circle].className = 'current';
}
// 10.自动播放轮播图
var timer = setInterval(function(){
// 手动调用事件
next.click();
},3000)
})