<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<style>
.carousel{
width: 600px;
height: 300px;
border:1px solid #000;
position:relative;
overflow: hidden;
margin:50px auto;
}
.carousel ul,.carousel ol{
list-style: none;
padding: 0;
margin: 0;
}
.carousel ul{
width: 3000px;
height: 300px;
position:absolute;
left:0;
top:0;
}
.carousel ul li{
float:left;
width: 600px;
height: 300px;
}
.carousel ul li a img{
width: 600px;
height: 300px;
}
.carousel ol{
height: 20px;
border-radius: 10px;
background-color:rgba(255,255,255,.7);
position: absolute;
bottom:10px;
left: 50%;
transform: translateX(-50%);
}
.carousel ol li{
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #000;
float:left;
margin: 5px;
}
.carousel ol li.active{
background-color: #f00;
}
.carousel:hover{
cursor: pointer;
}
.carousel>a{
width: 20px;
height: 40px;
color:#fff;
background-color:rgba(0,0,0,.7);
text-align: center;
line-height: 40px;
position:absolute;
top:50%;
transform: translateY(-50%);
text-decoration: none;
}
.carousel>a.leftBtn{
left: 0;
}
.carousel>a.rightBtn{
right: 0;
}
</style>
<body>
<div class="carousel">
<ul>
<li>
<a href="">
<img src="./images/1.jfif" alt="">
</a>
</li>
<li>
<a href="">
<img src="./images/2.webp" alt="">
</a>
</li>
<li>
<a href="">
<img src="./images/3.jfif" alt="">
</a>
</li>
</ul>
<ol>
<li class="active"></li>
<li></li>
<li></li>
</ol>
<a href="javascript:;" class="leftBtn"><</a>
<a href="javascript:;" class="rightBtn">></a>
</div>
</body>
<script src="./js/utils.js"></script>
<script>
// 1.获取元素
// 2.给ul的前后各复制一个li
// 3.调整ul的left值
// 4.开始轮播图效果 - 都是在操作下标 - 从右箭头点击开始
var ul = document.querySelector('.carousel ul');
// 复制
var firstLi = ul.firstElementChild.cloneNode(true)
// console.log(firstLi);
var lastLi = ul.lastElementChild.cloneNode(true)
// 分别放在末尾和最前面
ul.appendChild(firstLi)
ul.insertBefore(lastLi, ul.firstElementChild)
// 调整left
ul.style.left = -firstLi.offsetWidth + 'px'
// 获取ol
var ol = document.querySelector('.carousel ol');
// 定义下标
var index = 1
// 定义开关
var flag = true
// 右箭头点击
var rightBtn = document.querySelector('.carousel>a.rightBtn');
rightBtn.onclick = function(){
// 判断开关
if(!flag) return false
// 动画开始 - 开关关闭
flag = false
// 操作下标
index++;
// 让ul开始动画
animate(ul, {
left: -index * firstLi.offsetWidth
}, function(){
// 限制index 的最大值
if(index === ul.children.length-1){
index = 1
ul.style.left = -index * firstLi.offsetWidth + 'px'
console.log(-index * firstLi.offsetWidth);
}
// 动画结束后
// 操作小圆点
// 将所有小圆点的active去掉
for(var i=0;i<ol.children.length;i++){
ol.children[i].className = ''
}
// 给当前对应的小圆点添加active
ol.children[index-1].className = 'active'
// 动画结束 - 打开开关
flag = true
})
}
// 左箭头点击
var leftBtn = document.querySelector('.carousel>a.leftBtn');
leftBtn.onclick = function(){
if(!flag) return false
flag = false
// 操作下标
index--;
// 让ul开始动画
animate(ul, {
left: -index * firstLi.offsetWidth
}, function(){
// 限制index 的最大值
if(index === 0){
index = ul.children.length-2
ul.style.left = -index * firstLi.offsetWidth + 'px'
console.log(-index * firstLi.offsetWidth);
}
// 动画结束后
// 操作小圆点
// 将所有小圆点的active去掉
for(var i=0;i<ol.children.length;i++){
ol.children[i].className = ''
}
// 给当前对应的小圆点添加active
ol.children[index-1].className = 'active'
flag = true
})
}
// 小圆点点击
for(var j=0;j<ol.children.length;j++){
(function(j){
ol.children[j].onclick = function(){
if(!flag) return false
flag = false
index = j+1
animate(ul, {
left: -index * firstLi.offsetWidth
}, function(){
// 限制index 的最大值
if(index === 0){
index = ul.children.length-2
ul.style.left = -index * firstLi.offsetWidth + 'px'
console.log(-index * firstLi.offsetWidth);
}
// 动画结束后
// 操作小圆点
// 将所有小圆点的active去掉
for(var i=0;i<ol.children.length;i++){
ol.children[i].className = ''
}
// 给当前对应的小圆点添加active
ol.children[index-1].className = 'active'
flag = true
})
}
})(j)
}
// 自动轮播
var timerId = setInterval(function(){
rightBtn.onclick()
}, 500)
// 大盒子的移入移出
var carousel = document.querySelector('.carousel');
carousel.onmouseover = function(){
clearInterval(timerId)
}
carousel.onmouseout = function(){
timerId = setInterval(function(){
rightBtn.onclick()
}, 500)
}
</script>
</html>
/**
* 进行动画的函数
* @param {node} ele 要进行动画的元素
* @param {object} obj 动画的属性和值组成的键值对
* @param {function} fn 动画结束后要执行的函数
*/
function animate(ele, obj, fn){
// 定义计数器 - 计算有多少个定时器
var k = 0
// 动画 - 定时器
// 定时器的数量取决于obj中键值对数量
// 通过for in 遍历obj,在循环中创建定时器
for(var key in obj){
k++ // 统计定时器数量
// 在循环中嵌套了异步代码,异步代码中就无法准确的获取到每次遍历的变量了
// 在定时器中的key是循环结束以后的key - 使用自调用函数解决
(function(key){
var timerId = setInterval(function(){
// 获取left
// console.log(key);
var currentStyle = getComputedStyle(ele)[key] // 带px
var target = obj[key]
// 如果属性是opacity - 将当前的透明度扩大100被来处理
if(key === 'opacity'){
currentStyle *= 100
target *= 100
}
// 取整,将px去掉
currentStyle = parseInt(currentStyle)
// 因为有的距离远,有的距离近,所以以同样的速度动画,多个属性不均匀
// 每次走 剩下的距离 / 10 - 瑕疵:走不都头 - 取整
var speed = (target - currentStyle) / 20
// 取整 - 正数就向上取整,负数就向下取整
if(speed > 0){
speed = Math.ceil(speed)
}else{
speed = Math.floor(speed)
}
// 把数字加大
currentStyle += speed
// 限制left的最大值 - 将>=换成===,因为最后移动的距离,1px 1px 挪过去的,所以一定不会跳过目标值
// 将数字设置为box的left
if(key === 'opacity'){
ele.style[key] = currentStyle / 100
}else{
ele.style[key] = currentStyle + 'px'
}
if(currentStyle === target){
currentStyle = target
clearInterval(timerId)
// 每清除一次定时器,就让计数器--
k--
// 当k=0的时候,所有定时器就都结束了
if(k === 0){
// ele.style.backgroundColor = '#0f0'
// alert('动画结束')
// 希望这里的代码固定不变的,不要每次修改 - 每次都能满足调用的需求
fn()
}
}
}, 20)
})(key)
}
}
封装后代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<style>
.carousel{
width: 600px;
height: 300px;
border:1px solid #000;
position:relative;
overflow: hidden;
margin:50px auto;
}
.carousel ul,.carousel ol{
list-style: none;
padding: 0;
margin: 0;
}
.carousel ul{
width: 3000px;
height: 300px;
position:absolute;
left:0;
top:0;
}
.carousel ul li{
float:left;
width: 600px;
height: 300px;
}
.carousel ul li a img{
width: 600px;
height: 300px;
}
.carousel ol{
height: 20px;
border-radius: 10px;
background-color:rgba(255,255,255,.7);
position: absolute;
bottom:10px;
left: 50%;
transform: translateX(-50%);
}
.carousel ol li{
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #000;
float:left;
margin: 5px;
}
.carousel ol li.active{
background-color: #f00;
}
.carousel:hover{
cursor: pointer;
}
.carousel>a{
width: 20px;
height: 40px;
color:#fff;
background-color:rgba(0,0,0,.7);
text-align: center;
line-height: 40px;
position:absolute;
top:50%;
transform: translateY(-50%);
text-decoration: none;
}
.carousel>a.leftBtn{
left: 0;
}
.carousel>a.rightBtn{
right: 0;
}
</style>
<body>
<div class="carousel">
<ul>
<li>
<a href="">
<img src="./images/1.jfif" alt="">
</a>
</li>
<li>
<a href="">
<img src="./images/2.webp" alt="">
</a>
</li>
<li>
<a href="">
<img src="./images/3.jfif" alt="">
</a>
</li>
</ul>
<ol>
<li class="active"></li>
<li></li>
<li></li>
</ol>
<a href="javascript:;" class="leftBtn"><</a>
<a href="javascript:;" class="rightBtn">></a>
</div>
</body>
<script src="./js/utils.js"></script>
<script>
// 1.获取元素
// 2.给ul的前后各复制一个li
// 3.调整ul的left值
// 4.开始轮播图效果 - 都是在操作下标 - 从右箭头点击开始
var ul = document.querySelector('.carousel ul');
// 复制
var firstLi = ul.firstElementChild.cloneNode(true)
// console.log(firstLi);
var lastLi = ul.lastElementChild.cloneNode(true)
// 分别放在末尾和最前面
ul.appendChild(firstLi)
ul.insertBefore(lastLi, ul.firstElementChild)
// 调整left
ul.style.left = -firstLi.offsetWidth + 'px'
// 获取ol
var ol = document.querySelector('.carousel ol');
// 定义下标
var index = 1
// 定义开关
var flag = true
// 右箭头点击
var rightBtn = document.querySelector('.carousel>a.rightBtn');
rightBtn.onclick = function(){
// 判断开关
if(!flag) return false
// 动画开始 - 开关关闭
flag = false
// 操作下标
index++;
move()
}
// 左箭头点击
var leftBtn = document.querySelector('.carousel>a.leftBtn');
leftBtn.onclick = function(){
if(!flag) return false
flag = false
// 操作下标
index--;
// 让ul开始动画
move()
}
// 小圆点点击
for(var j=0;j<ol.children.length;j++){
(function(j){
ol.children[j].onclick = function(){
if(!flag) return false
flag = false
index = j+1
move()
}
})(j)
}
// 自动轮播
var timerId
auto()
// 大盒子的移入移出
var carousel = document.querySelector('.carousel');
carousel.onmouseover = function(){
clearInterval(timerId)
}
carousel.onmouseout = function(){
auto()
}
// 封装轮播核心代码
function move(){
animate(ul, {
left: -index * firstLi.offsetWidth
}, function(){
// 限制index 的最大值
if(index === 0){
index = ul.children.length-2
ul.style.left = -index * firstLi.offsetWidth + 'px'
console.log(-index * firstLi.offsetWidth);
}
if(index === ul.children.length-1){
index = 1
ul.style.left = -index * firstLi.offsetWidth + 'px'
console.log(-index * firstLi.offsetWidth);
}
// 动画结束后
// 操作小圆点
// 将所有小圆点的active去掉
for(var i=0;i<ol.children.length;i++){
ol.children[i].className = ''
}
// 给当前对应的小圆点添加active
ol.children[index-1].className = 'active'
flag = true
})
}
// 封装自动轮播
function auto(){
timerId = setInterval(function(){
rightBtn.onclick()
}, 500)
}
</script>
</html>