原生js实现轮播图
先来看看效果图。
样式就没过多写,知道是什么就行了,随时都可以改的。
移动方式是css属性里的transform:translate(),然后用setTimeout这个定时器来实现的。
有一下几个效果:
- 自动轮播。
- 移入/移出暂停/开始轮播.
- 点击左右按钮进行切换。
- 点击小点点进行切换。
我的思路是假如有5张图片,最后一张在第一位,展示区域展示第二个图片。
就是说现在是5 1 2 3 4的顺序,显示的是1那一个图片。给个思路图吧。
图一是向左。图二向右
图一
图二
下面先来看一看CSS和HTML代码吧,
HTML
<div id="app">
<!-- 左右按钮-->
<div id="left" class="left arrowhead">
<div>
左
</div>
</div>
<div id="right" class="right arrowhead">
<div>右</div>
</div>
<!-- 切换小点点-->
<ul class="subscript">
</ul>
<!-- 切换内容-->
<div class="content">
</div>
</div>
代码里没图片?
等会在js里加。
CSS
html,
body {
width: 100%;
height: 100%;
background: pink;
}
ul,
li {
padding: 0;
margin: 0;
}
/*主盒子*/
#app {
width: 700px;
height: 400px;
overflow: hidden;
background: red;
margin: 0 auto;
position: relative;
}
/*左右按钮*/
.left {
margin-left: 20px;
}
.right {
right: 0;
margin-right: 20px;
}
.arrowhead {
height: 100%;
display: flex;
align-items: center;
position: absolute;
z-index: 2;
font-weight: 700;
}
.arrowhead div {
border-radius: 50%;
background: #eee;
padding: 10px;
}
/*轮播内容*/
.content {
height: 100%;
text-align: center;
line-height: 400px;
display: flex;
position: absolute;
left: -700px;
}
/*轮播图*/
img {
width: 700px;
height: 100%;
}
/*轮播小点点*/
.subscript {
width: 100%;
height: 10px;
position: absolute;
bottom: 0;
z-index: 2;
box-sizing: border-box;
padding: 10px;
display: flex;
justify-content: center;
align-items: center;
}
.subscript li {
width: 10px;
height: 10px;
border-radius: 50%;
background: pink;
list-style: none;
margin: 0 5px 0 5px;
}
/*小点点当前位置的样式*/
.subscript .active {
background: red;
}
现在改有的样式都有了,觉得不好看的话可以自行添加。
现在就是重点js部分了.
获取dom
首先就是获取dom.
let left = document.getElementById('left')//左
let right = document.getElementById('right')//右
let app = document.getElementById('app')//主盒子
let content = document.getElementsByClassName('content')[0]//内容区域
let subscript = document.getElementsByClassName('subscript')[0]//小点点
只需要获取五个盒子就行。
创建图片并插入
创建图片数组,任意数量的图片,计算content盒子的宽,并且将图片放入到content里去。再循环出小点点,再分别给content和subscript的子元素添加上标记。然后将第一个小点点加上样式。
//创建图片数组
let imgs = [
"图片路径自行添加",
"图片路径自行添加",
"图片路径自行添加",
"图片路径自行添加",
...
]
//计算滚动盒子宽度
content.style.width = `${(imgs.length) * 700}px`
//创建图片dom
const str = imgs.map(img => `<img src="${img}" />`).join('');
//创建小点点dom
const str2 = imgs.map(() => '<li class="list"></li>').join('');
//插入父盒子和小点点
content.innerHTML = str;
subscript.innerHTML = str2;
//给小点点添加下标
for (let i = 0; i < subscript.children.length; i++) {
subscript.children[i].setAttribute('index', i)
}
//给content子元素添加下标
for (let i = 0; i < content.children.length; i++) {
content.children[i].setAttribute('index', i)
}
//个第一个添加上样式
subscript.children[0].classList.add('active')
定义变量
定义三个变量来控制轮播图,分别是定时器,方向和自动循环的开关。
// 定义一个变量用来存储定时器
let time = null;
// 定义一个变量用来存储轮播方向
let direction = 'left'
//定义一个变量用来存储开关
let flag = false
//延迟变量
let delay=1000
轮播相关的函数
我定义了三个函数,
- 第一个会有一个参数,参数是时间/毫秒,调用时先清理掉定时器,
- 然后用延时定时器调用carousel函数,此函数是一个设置过渡效果的函数,他有一个参数分别是-1(左)和1(右),当为-1时transform:translateX(-700px)就会向左平移,当为1时transform:translateX(700px)就会向右平移,这样我们就可以判断当前是在向哪个方向轮播,后面设置左右按钮就只需要调用并传参就行了,然后将direction设置为当前的方向后面会用。
//定义一个函数控制函数轮播时间
function play() {
clearTimeout(time);
time = setTimeout(() => carousel(-1), delay);
}
//启用轮播定时器
play();
//平移函数
function carousel(num) {
clearTimeout(time);
//设置过渡
content.style.transition = "all .35s ease";
//设置content平移
content.style.transform = `translateX(${700 * num}px)`;
//判断轮播方向
direction = num == -1 ? 'left' : 'right'
}
//定义小点点样式函数
function subscriptStyle(indexContent) {
//清除所有小点点样式
for (let i = 0; i < subscript.children.length; i++) {
subscript.children[i].classList.remove('active')
}
//因为是从第二个开始轮播,所以要减一,不然小点点是从第二个开始的
let num = +indexContent - 1
//当下标为-1时,让下标为数组长度的最后一个,即最后一张图片
//由于上面同步了错位-1,导致小点点不会显示最后一个,就是说0-1时是没有东西的但最后一个点又没显示所以当他等于-1时就给最后一个小点点添加上样式
//例如:
//content(图片): 0 1 2 3 4
//subscript(小点点):0 1 2 3 4
//显示的是1,为了同步content-1然后就成了
//-1 0 1 2 3
// 0 1 2 3 4
//然后获取第当前显示图片的下标就是0,并设置同样下标为0的小点点可以看到显示的图片下标和小点点的下标是错开的所以4就对应-1
if (num == -1) num = content.children.length - 1
//给当前小点点添加样式
subscript.children[num].classList.add('active')
}
移动相关的函数
上面的调用后只能移动一个就没了,下面的函数就是关键了
- 第一个是移动图片函数,就是判断direction是不是"left"字段是就将第一个恶图片放到最后不是就将最后的图片放到第一位
- 第二个是监听过渡结束事件,当过渡结束后先禁掉过渡,不然调用moveCarousel函数进行图片换位时会有一个回往回过渡的过程,然后将平移清除就。
- 判断当前鼠标是否在轮播图区域内在的话过渡结束就重新调用play函数就会形成无限循环的情况,就是切换手动和自动。
- 然后就是调用清除小点点样式函数了,清除掉全部点点的样式,给与当前图片相同标记的小点点加上样式。
//移动图片函数
function moveCarousel() {
const child = direction === "left" ? content.children[0] : content.lastElementChild;
content.removeChild(child);
direction === "left" ? content.appendChild(child) : content.prepend(child);
}
//监听过渡结束
content.addEventListener("transitionend", () => {
//禁掉过渡动画
content.style.transition = "none";
moveCarousel()
//重置translateX值,取消过渡效果
content.style.transform = "none";
//当开关为true时不执行play
if (!flag) play()
//让小点点的样式跟着变
subscriptStyle(content.children[1].getAttribute('index'))
})
监听左右按钮点击事件
点击后调用carousel平移函数,并传入相应的值来判断左/右,-1/1.
//监听点击事件
left.addEventListener("click", () => {
carousel(-1)
});
right.addEventListener("click", () => {
carousel(1)
});
监听小点点点击事件
判断是否是点击的小点点是就获取下标、获取当前显示图片的下标计算差值,然后禁掉过渡动画,因为这时候就直接跳图片就行了不需要过渡动画了,
然后再循环调用moveCarousel函数content.children的长度减去差值在加1次就是想要跳转的图片了,加1是因为之前与小点点同步时-1了让第二张当成第一张来显示,反过来控制就会少跳一次所以得加1。这里可以多些一点判断正负来调用moveCarousel函数是向左还是向右跳这样可以少执行几次代码,由于效果已经出来了就懒得弄了。
subscriptStyle传参加1是因为函数内部减1了会导致点击时少一位所以得加1
//给小点点绑定点击事件
subscript.addEventListener("click", (e) => {
if (e.target.className === "list") {
//获取点击的小点点下标
const index = e.target.getAttribute('index')
//获取content子元素下标,当前显示的图片下标
const indexContent = content.children[1].getAttribute('index')
//计算点击的小点点和当前显示的图片的下标差值
const num = indexContent - index
//禁掉过渡动画
content.style.transition = "none";
//根据差值判断循环跳转几次
for (let i = 0; i < (content.children.length - num) + 1; i++) moveCarousel("left")
//让小点点的样式跟着变
subscriptStyle(+index + 1)
}
})
监听移入移出事件
引入轮播图时暂停定时器,将开关打开,这样就不会在点击完后监听过渡结束后调用play函数让其变为自动轮播,移出就关闭并调用play函数。
//移入app盒子停止轮播
app.addEventListener("mouseenter", () => {
clearTimeout(time);
flag = true
// 移出app盒子继续轮播
app.addEventListener("mouseleave", () => {
flag = false
play()
})
})
结束,代码到这里就完成了。
如果不想复制可以在我的GitHub仓库里下载。
这是源码地址:GitHub
代码利用延迟定时器进行平移过渡的实现,然后监听过渡结束后将图片换位,然后再次调用延时定时器,来实现无限循环,不需要记录当前图片是第几个。
这里是提供一下我在网上没找到的写轮播图的思路,希望能对您有所帮助。
代码有什么问题,或写的不够好欢迎在评论区提出。