原生js实现轮播图
每一步都解释很详细
话不多说 上源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../js/animate.js"></script>
<style>
* {
padding: 0;
margin: 0;
}
li {
list-style: none;
}
img {
vertical-align: top;
}
.wrapAll {
width: 1226px;
height: 460px;
margin: 0 auto;
margin-top: 100px;
position: relative;
overflow: hidden;
}
.slideBar {
height: 460px;
/* width: 4904px; */
width: max-content;
position: absolute;
left: 0;
}
.slideBar li {
width: 1226px;
float: left;
}
.dotList {
position: absolute;
right: 50px;
bottom: 20px;
display: flex;
}
.dotList li {
width: 15px;
height: 15px;
background-color: #fff;
margin: 5px;
border-radius: 50%;
}
.dotList .active {
background-color: blue;
}
.left,
.right {
width: 40px;
height: 80px;
background-color: rgba(0, 0, 0, 0.6);
position: absolute;
z-index: 999;
}
.left {
left: 0;
top: 50%;
transform: translateY(-50%);
/* margin-top:-40px; */
}
.right {
right: 0;
top: 50%;
transform: translateY(-50%);
}
</style>
</head>
<body>
<div class="wrapAll">
<ul class="slideBar">
<li><img src="../images/1.jpg" alt=""></li>
<li><img src="../images/2.jpg" alt=""></li>
<li><img src="../images/3.jpg" alt=""></li>
<li><img src="../images/4.jpg" alt=""></li>
<li><img src="../images/1.jpg" alt=""></li>
</ul>
<ul class="dotList">
<li class="active"></li>
<li></li>
<li></li>
<li></li>
</ul>
<div class="right"></div>
<div class="left"></div>
</div>
</body>
<script>
var wrapAll = document.querySelector(".wrapAll");
var slideBar = document.querySelector(".slideBar");
var slideBarList = document.querySelectorAll(".slideBar li");
var liList = document.querySelectorAll(".dotList li");
var left = document.querySelector(".left");
var right = document.querySelector(".right");
var index = 0; //定义一个全局变量 索引
var timer = null; //定义一个全局timer 用来记时
var clientWidth = slideBarList[0].clientWidth; //获取图片的宽度
autoPlay();
for (let i = 0; i < liList.length; i++) { //循环遍历 获取小圆点
let li = liList[i];
li.onclick = function () { // 圆点li的点击事件
index = i;
for (var j = 0; j < liList.length; j++) { //先清除所有效果
liList[j].className = "";
}
liList[i].className = "active"; //给对应的点击的li赋予效果
animate(slideBar, "left", -clientWidth * index, "ease-out"); //公共样式animate.js 属性 属性值 终点 运动方式
}
}
left.onclick = function () { //左边点击事件
index--;
auto();
}
right.onclick = function () { //右边点击事件
index++;
auto();
}
wrapAll.onmouseenter = function () { //鼠标移入
clearInterval(timer);
}
wrapAll.onmouseleave = function () { //鼠标移出
autoPlay();
}
function autoPlay() {
clearInterval(timer); //清除计时器防止连续点击或移动触发的问题
timer = setInterval(function () {
index++;
auto();
}, 3000)
}
function auto() {
//这么写的目的是防止有用户连续点击向左或者向右 所产生的问题
if (index < 0) { //点击向左运动 如果索引小于0 那么把index变成最后一个索引
index = slideBarList.length - 1;
slideBar.style.left = -clientWidth * index + "px"; //此时left值为第五张图片所在
index--; //变成第四张我们所需要的图片
}
if (index >= slideBarList.length) { //点击向左运动 如果索引大于slideBarList长度 此时最长的是第五张照片 也就是第一张
slideBar.style.left = 0; //利用视觉差跳回第一张图片
index = 0; //索引为第一张
index++; //索引增加
}
for (var j = 0; j < liList.length; j++) { //循环遍历清除li的效果
liList[j].className = "";
}
liList[index >= slideBarList.length - 1 ? 0 : index].className = "active"; //给对应的li增添效果
animate(slideBar, "left", -clientWidth * index, "ease-out", function () {
if (index >= slideBarList.length - 1) {
slideBar.style.left = 0;
index = 0;
}
})
}
</script>
</html>
animate.js文件
function animate(ele, attr, end, aniType, fn) { // 1000
// var cur = ele.offsetLeft; // 初始值 记录盒子当前的位置(left)
var cur = parseFloat(getStyle(ele, attr)); // 初始值 记录盒子当前的位置(left)
var end = parseFloat(end);
if (attr == "opacity") { // 如果是opacity 取值时 扩大100倍
cur *= 100;
end *= 100;
}
// cur
// 1. 点击时 记录盒子的初始位置 (初始值)
// 2. 每隔固定的时间,进行累加/累减 (记录每次运动之后位置)
var speed = 0;
// 问题 公用一个全局timer 多个元素同时运动时 会相互影响
// ele 元素节点 => 本质(对象) => 可以自定义属性
// 解决办法 : 把计时器的编号存到元素自己本身上
clearInterval(ele.timer);
ele.timer = setInterval(function () {
if (aniType == "linear") {
// 匀速运动 linear (normal)
speed = end > cur ? 20 : -20;
} else if (aniType == "ease-in") {
// 加速 ease-in (fast)
// end > cur ? speed++ : speed--;
speed = end > cur ? speed + 5 : speed - 5;
} else if (aniType == "ease-out") {
// 缓冲运动 ease-out (slow)
// (终点值 - 当前值)/缓冲因子 => 剩余的距离 / 缓冲因子
// 缓冲因子 一般在8-12
// 正向运动 (0-1000 speed正值)
// speed = (end - cur) / 10;
// speed = Math.ceil(speed); // 0.1111 => 1
// console.log(speed);
// 反向运动 (1000-0 speed负值)
// speed = (end - cur) / 10;
// speed = Math.floor(speed); // -0.11111 => -1
// console.log(speed);
speed = (end - cur) / 10;
speed = end > cur ? Math.ceil(speed) : Math.floor(speed);
}
cur += speed;
if (attr == "opacity") { // 如果是opacity 赋值时 缩小100倍
ele.style[attr] = cur / 100;
} else {
ele.style[attr] = cur + "px";
}
// 临界值
if (Math.abs(end - cur) < Math.abs(speed)) { // 理想情况 cur == end
clearInterval(ele.timer);
if (attr == "opacity") { // 如果是opacity 赋值时 缩小100倍
ele.style[attr] = end / 100;
} else {
ele.style[attr] = end + "px";
}
if (fn) { // 本次运动结束 如果传入了函数 就执行
fn();
}
}
}, attr == "opacity" ? 50 : 10);
}
function getStyle(ele, attr) {
if (window.getComputedStyle) {
return window.getComputedStyle(ele)[attr];
} else {
return ele.currentStyle[attr];
}
}
图片