原生js实现轮播图,说难不难,说简单不简单。基础套路还是来复习一下吧。先看图。
先看html结构!很简单!
<div class="slider">
<div class="slide-item slide-item-1">1</div>
<div class="slide-item slide-item-2">2</div>
<div class="slide-item slide-item-3">3</div>
<div class="slide-item slide-item-4">4</div>
</div>
来分析一下轮播图的css逻辑。
轮播图容器,重点 position:relative;overflow: hidden;其他样式可以自定义
.slider {
width: 100%;
height: 300px;
position: relative;
overflow: hidden;
margin: 0 auto;
}
轮播图子项,重点 left:-100%达到隐藏效果。
.slide-item {
display: inline-block;
width: 100%;
height: 100%;
position: absolute;
left: -100%; /* 隐藏 */
}
.slide-item:first-child { /* 首项不隐藏 */
left: 0;
}
写划入划出动画(下一张动画效果),包括反向划入划出动画(上一张动画效果)
@keyframes slideIn {
from { left: 100%; }
to { left: 0; }
}
@keyframes slideOut {
from { left: 0; }
to { left: -100%; }
}
@keyframes slideInReverse {
from { left: -100%; }
to { left: 0; }
}
@keyframes slideOutReverse {
from { left: 0; }
to { left: 100%; }
}
一切工具准备齐全。来上大刀,js!
轮播图的逻辑很简单。首先整理轮播的元素items。假设现在有五个轮播元素。可以将items划分为两个数组。
1. activeIndex = [0,1] // activeIndex[0] 表示当前元素的下标 ,activeIndex[1] 表示下一个将划入的元素下标
2. waitIndex = [2,3,4] // waitIndex表示等待轮播队列
let slider = document.querySelector('.slider')
let slideItems = slider.getElementsByClassName('slide-item');
let activeIndex = [0, 1]
let waitIndex = []
if (slideItems.length > 2) {
for (let i = 2; i < slideItems.length; i++) {
waitIndex.push(i)
}
}
接下来追加轮播小点点和左右方向箭头dom元素
function initDotAndArrow(num) {
let str = '<div class="dot-panel">'
for (let i = 0; i < num; i++) {
if (i === 0) {
str += '<div class="dot dot-active"></div>'
} else {
str += '<div class="dot"></div>'
}
}
str += '</div>'
str += `<div class="arrow-panel pre-panel">
<div class="arrow left-arrow"></div>
</div>
<div class="arrow-panel next-panel">
<div class="arrow right-arrow"></div>
</div>`
let old = slider.innerHTML
slider.innerHTML = old + str
}
initDotAndArrow(slideItems.length)
先定义一些变量,方便轮播的后续操作
let pre = slider.getElementsByClassName('left-arrow')[0]
let next = slider.getElementsByClassName('right-arrow')[0]
let dot = slider.getElementsByClassName('dot')
let slideIn = 'slideIn 2s ease forwards'
let slideOut = 'slideOut 2s ease forwards'
let slideInReverse = 'slideInReverse 2s ease-in-out forwards'
let slideOutReverse = 'slideOutReverse 2s ease-in-out forwards'
let ticker;
这样有了activeIndex 和waitIndex 这两个数组,一切都清晰明了了,实现轮播这个动作就是去操作这两个数组。
轮播的动作可以切割为四个子动作即几个函数:下一张 / 上一张 / 开始 / 停止
1. 下一张:进场目标是activeIndex[1], 退场目标是activeIndex[0]。为这两个目标增加动画。进退场完毕,需要改变activeIndex,waitIndex了。
function toNext() {
let current = activeIndex[0]
let target = activeIndex[1]
slideItems[current].style.animation = slideOut
slideItems[target].style.animation = slideIn
activeIndex[0] = target
activeIndex[1] = waitIndex.length > 0 ? waitIndex[0] : current
if (waitIndex.length > 0) {
waitIndex.push(current)
waitIndex.splice(0, 1)
}
dot[current].className = 'dot'
dot[target].className = 'dot dot-active'
}
2. 上一张:进场目标是waitIndex末尾(需要判断waitIndex是否为空数组),退场目标是activeIndex[0]。为这两个目标增加动画
function toPre() {
let current = activeIndex[0]
let next = activeIndex[1]
let target = waitIndex.length > 0 ? waitIndex[waitIndex.length - 1] : activeIndex[1]
slideItems[current].style.animation = slideOutReverse
slideItems[target].style.animation = slideInReverse
activeIndex[0] = target
activeIndex[1] = current
if (waitIndex.length > 0) {
for (let i = 0; i < waitIndex.length; i++) {
let f = waitIndex[i] - 1
waitIndex[i] = f < 0 ? slideItems.length - 1 : f
}
}
dot[current].className = 'dot'
dot[target].className = 'dot dot-active'
}
3.开始轮播
function play() {
ticker = setInterval(function () {
toNext()
}, duration)
}
4.停止轮播
function pause() {
clearInterval(ticker)
}
轮播事件构建完成了。加上DOM操作吧
pre.onclick = function () {
toPre()
}
next.onclick = function () {
toNext()
}
slider.onmouseenter = function () {
clearInterval(ticker)
}
slider.onmouseleave = function () {
play()
}
最后整一个轮播函数如下
function cl_slider(obj) {
const D = document
let slider = D.querySelector(obj.element)
let slideItems = slider.getElementsByClassName('slide-item');
let activeIndex = [0, 1]
let waitIndex = []
let duration = obj.duration?obj.duration:4500
if (slideItems.length > 2) {
for (let i = 2; i < slideItems.length; i++) {
waitIndex.push(i)
}
}
function initDotAndArrow(num) {
let str = '<div class="dot-panel">'
for (let i = 0; i < num; i++) {
if (i === 0) {
str += '<div class="dot dot-active"></div>'
} else {
str += '<div class="dot"></div>'
}
}
str += '</div>'
str += `<div class="arrow-panel pre-panel">
<div class="arrow left-arrow"></div>
</div>
<div class="arrow-panel next-panel">
<div class="arrow right-arrow"></div>
</div>`
let old = slider.innerHTML
slider.innerHTML = old + str
}
initDotAndArrow(slideItems.length)
let pre = slider.getElementsByClassName('left-arrow')[0]
let next = slider.getElementsByClassName('right-arrow')[0]
let dot = slider.getElementsByClassName('dot')
let slideIn = 'slideIn 2s ease forwards'
let slideOut = 'slideOut 2s ease forwards'
let slideInReverse = 'slideInReverse 2s ease-in-out forwards'
let slideOutReverse = 'slideOutReverse 2s ease-in-out forwards'
let ticker;
function play() {
ticker = setInterval(function () {
toNext()
}, duration)
}
function toNext() {
let current = activeIndex[0]
let target = activeIndex[1]
slideItems[current].style.animation = slideOut
slideItems[target].style.animation = slideIn
activeIndex[0] = target
activeIndex[1] = waitIndex.length > 0 ? waitIndex[0] : current
if (waitIndex.length > 0) {
waitIndex.push(current)
waitIndex.splice(0, 1)
}
dot[current].className = 'dot'
dot[target].className = 'dot dot-active'
}
function toPre() {
let current = activeIndex[0]
let next = activeIndex[1]
let target = waitIndex.length > 0 ? waitIndex[waitIndex.length - 1] : activeIndex[1]
slideItems[current].style.animation = slideOutReverse
slideItems[target].style.animation = slideInReverse
activeIndex[0] = target
activeIndex[1] = current
if (waitIndex.length > 0) {
for (let i = 0; i < waitIndex.length; i++) {
let f = waitIndex[i] - 1
waitIndex[i] = f < 0 ? slideItems.length - 1 : f
}
}
dot[current].className = 'dot'
dot[target].className = 'dot dot-active'
console.log(activeIndex, waitIndex);
}
play()
pre.onclick = function () {
toPre()
}
next.onclick = function () {
toNext()
}
slider.onmouseenter = function () {
clearInterval(ticker)
}
slider.onmouseleave = function () {
play()
}
}
调用方法也很简单。
let myslider = cl_slider({
element: '.slider', // 轮播图容器
duration: 2500, // 播放间隔(ms),默认4500ms
})