SOURCE

console 命令行工具 X clear

                    
>
console
class Carousel{

    // 当前被选中的索引
    current = 0
    // 存储所有li结点
    arr = []
    // 默认设置
    default = {
        // 图片宽度
        width: 150,
        // 图片高度
        height: 150,
        // 填充
        padding: 25,
        // 展示图片数量
        previewCount: 5,
        // 动画速度
        speed: 200,
        // 图片数据
        datas: null
    }

    constructor (selector, options) {
        if (!selector) {
            return
        }
        Object.assign(this.default,options)
        this.$ele = document.querySelector(selector)
    }

    // 初始化
    init () {
        if (this.default.datas.length < this.default.previewCount) {
            return
        }
        this._optimize()
        this._createDom()
        this._initDom()
    }

    // 这里是为了动画优化
    _optimize () {
        const length = this.default.datas.length
        const fix = parseInt(this.default.previewCount / 2)
        const prefixs = this.default.datas.slice(length - fix,length)
        let count = length - this.default.previewCount
        let suffixs = []
        if (count < fix) {
            suffixs = this.default.datas.slice(0, fix - count)
        }
        this.current = Math.ceil((fix + this.default.previewCount) / 2)
        this.$fix = fix
        this.default.datas = [...prefixs,...this.default.datas,...suffixs]
    }

    // 创建dom css
    _createDom () {
        const width = (this.default.width + this.default.padding * 2) * this.default.previewCount
        this.$ele.style.width = `${width}px`
        this.$ele.style.position = 'relative'
        this.$ele.style.overflow = 'hidden'
        this.$ele.style.padding = '100px 0'
        this._createUl()
        const length = this.default.datas.length
        for (let i = 0; i < length; i++) {
            const li = this._createLi(i)
            li.appendChild(this._createImg(i))
            // 设置当前选中的
            if (i === this.current) {
                li.firstChild.style.filter = 'grayscale(0)'
                li.firstChild.style.transform = 'scale(2)'
                const bg = li.getAttribute('data-bg')
                this.$ele.style.backgroundImage = `url('${bg}')`
                this.$ele.style.backgroundRepeat = 'no-repeat'
            }
            this.$ul.appendChild(li)
        }
        this.$ele.appendChild(this.$ul)
    }

    // 创建ul标签
    _createUl () {
        const width = (this.default.width + this.default.padding * 2) * this.default.datas * 2
        this.$ul = document.createElement('ul')
        this.$ul.style.width = `${width}px`
        this.$ul.style.height = `${this.default.height}px`
        this.$ul.style.position = 'relative'
        this.$ul.style.listStyleType = 'none'
    }

    // 创建li标签
    _createLi (index) {
        const offset = index - this.$fix
        const boxWidth = this.default.width + this.default.padding * 2
        this.$offset = boxWidth
        const li = document.createElement('li')
        li.style.cssFloat = 'left'
        li.style.cursor = 'pointer'
        li.style.padding = `${this.default.padding}px`
        li.style.position = 'absolute'
        li.style.top = '0'
        li.style.left = `${ offset * boxWidth}px`
        li.setAttribute('data-bg',this.default.datas[index].bg)
        li.setAttribute('data-index', index)
        // 添加点击事件
        const self = this
        li.addEventListener('click',function () {
            const left = parseInt(li.style.left)
            const currentLeft = parseInt(self.arr[self.current].style.left)
            if (left > currentLeft) {
                self.nextMove((left - currentLeft) / self.$offset)
            } else if (currentLeft > left){
                self.preMove((currentLeft - left) / self.$offset)
            }
        })
        return li
    }

    // 创建img标签
    _createImg (index) {
        const img = document.createElement('img')
        img.style.width = `${this.default.width}px`
        img.style.height = `${this.default.height}px`
        img.style.filter = 'grayscale(1)'
        img.style.transform = 'scale(1)'
        img.setAttribute('src', this.default.datas[index].src)
        return img
    }

    _initDom () {
        const lis = document.querySelectorAll('li')
        const length = lis.length
        for (let i = 0;i < length; i ++) {
            this.arr[i] = lis[i]
        }
    }

    // 上N个
    // step: 向前运动步骤
    preMove (step = 1) {
        let loop = 0
        const target = 1
        while(loop < step){
            loop ++
            const dom = this.arr.pop()
            dom.style.left = `${- (loop + this.$fix) * this.$offset}px`
            this.arr.unshift(dom)
        }
        this._setUp(target * loop)
    }

    // 下N个
    nextMove (step = 1) {
        let loop = 0
        const target = -1
        while(loop < step){
            const dom = this.arr.shift()
            dom.style.left = `${(this.default.datas.length + loop - this.$fix) * this.$offset}px`
            this.arr.push(dom)
            loop ++
        }
        this._setUp(target * loop)
    }

    _setUp (target) {
        for (let i = 0; i < this.arr.length; i ++) {
            this.$ul.appendChild(this.arr[i])
        }
        for (let i = 0; i < this.arr.length; i ++) {
            this._move(this.arr[i], target, i)
        }
    }

    // 运动
    _move (dom, target = -1, index) {
        const self = this
        clearInterval(dom.timer)
        const left = parseFloat(dom.style.left)
        let scale = parseFloat(dom.firstChild.style.transform.substring(6, 7))
        let gray = parseFloat(dom.firstChild.style.filter.substring(10, 11))
        let offset = 0
        const sign = parseInt(scale) === 1 ? 1 : -1
        const offsetVal = target * this.default.speed / 30
        const scaleVal = sign * 1 / 30
        let stop = false
        // 切换背景
        if (self.current === index) {
            const bg = dom.getAttribute('data-bg')
            this.$ele.style.backgroundImage = `url('${bg}')`
            this.$ele.style.backgroundRepeat = 'no-repeat'
        }
        // 执行动画
        dom.timer = setInterval(function () {
            offset += offsetVal
            if (sign < 0 || self.current === index) {
                scale += scaleVal
                gray -= scaleVal
            }
            if (Math.abs(offset) >= Math.abs(target * self.$offset)) {
                offset = target * self.$offset
                if (self.current === index) {
                    scale = 2
                    gray = 0
                } else {
                    scale = 1
                    gray = 1
                }
                stop = true
            }
            dom.style.left = `${left + offset}px`
            dom.firstChild.style.transform = `scale(${scale})`
            dom.firstChild.style.filter = `grayscale(${gray})`
            if (stop) {
                clearInterval(dom.timer)
            }
        }, 30)
    }

    // 自动
    // 每5秒运动2步
    auto () {
        const self = this
        setInterval(function () {
            self.preMove(2)
        }, 5000)
    }
}

window.onload = function () {
    const carousel = new Carousel('#carousel',{
        datas: [
            {bg: './images/b1.jpg', src: './images/1.png'},
            {bg: './images/b2.jpg', src: './images/2.png'},
            {bg: './images/b3.jpg', src: './images/3.png'},
            {bg: './images/b4.jpg', src: './images/4.png'},
            {bg: './images/b5.jpg', src: './images/5.png'},
            {bg: './images/b6.jpg', src: './images/6.png'},
        ]
    })
    carousel.init()
}
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
    <meta charset="UTF-8">
    <title>轮播图</title>
    <link href="./index.css" rel="stylesheet">
</head>
<body>
<div id="carousel"></div>
<script src="./index.js"></script>
</body>
</html>
* {
    margin: 0;
    padding: 0;
}
body {
    margin: 0;
    padding: 0;
    display:flex;
    align-items:center;
    justify-content: center;
    height: 100vh;
    width: 100vw;
}