面试官:手写一个轮播图?(原生)

821 阅读1分钟

一、前言

前几日,笔者的朋友参加面试,面试官让手写一个轮播图,顿时懵了......想当初,我的轮播图也是写贼溜,这平时 cv 惯了,谁还记得?于是乎,有了下文......

二、手写轮播图

1、复杂版,用于理解轮播图的逻辑

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        a {
            text-decoration: none;
        }

        li {
            list-style: none;
        }

        .box {
            position: relative;
            width: 590px;
            margin: 100px auto;
        }

        .focus {
            width: 590px;
            height: 470px;
        }

        .prev,
        .next {
            position: absolute;
            top: 0;
            bottom: 0;
            margin: auto;
            display: block;
            width: 30px;
            height: 30px;
            line-height: 30px;
            text-align: center;
            background-color: rgba(0, 0, 0, 0.3);
            font-size: 20px;
            font-family: simsun;
            color: #fff;
            cursor: pointer;
        }

        .prev {
            left: 0;
            border-radius: 0 10px 10px 0;
        }

        .next {
            right: 0;
            border-radius: 10px 0 0 10px;
        }

        .dotted {
            position: absolute;
            left: 0;
            right: 0;
            bottom: 20px;
            margin: auto;
            width: 150px;
            height: 20px;
        }

        .dotted ul {
            display: flex;
            justify-content: space-around;
        }

        .dotted li {
            cursor: pointer;
            width: 10px;
            height: 10px;
            background-color: #fff;
            border-radius: 50%;
        }

        .dotted li.current {
            background-color: orange;
        }
    </style>
</head>

<body>
    <div class="box">
        <!-- 焦点图 -->
        <div class="focus">
            <ul>
                <li><a href=""><img src="./imges/1.jpg" alt=""></a></img></li>
            </ul>
        </div>
        <!-- 上一页 -->
        <div class="prev"></div>
        <!-- 下一页 -->
        <div class="next"></div>
        <!-- 小圆圈 -->
        <div class="dotted">
            <ul>
                <li class="current"></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
            </ul>
        </div>

    </div>
    <script>
        // 0.存储图片
        let imgArr = [
            './imges/1.jpg',
            './imges/2.jpg',
            './imges/3.jpg',
            './imges/4.jpg',
            './imges/5.jpg',
            './imges/6.jpg',
            './imges/7.jpg',
            './imges/8.jpg']

        // 1.获取数据
        let prev = document.querySelector('.prev')//上一页
        let next = document.querySelector('.next')//下一页
        let liList = document.querySelectorAll('.dotted li')//小圆圈//伪数组
        let img = document.querySelector('.focus img')//获取大图
        let box = document.querySelector('.box')//为后面做铺垫,鼠标移入大盒子,停止轮播

        // 2.测试数据是否获取
        console.log(prev, next, liList, img, box)
        
        //◆全局变量,图片切换做准备(非常重要)
        let index = 0

        // 3.注册事件
        // 3.1鼠标移入小li
        for (let i = 0; i < liList.length; i++) {
            liList[i].onmouseenter = function () {
                // 图片的 src 重新赋值
                img.src = imgArr[i]
                // 上一个 li 移除样式
                document.querySelector('.dotted li.current').classList.remove('current')
                // 当前的 li 添加样式
                liList[i].classList.add('current')
                // 存储下标(不存储下标的话,每次点击上一页下一页,下标都是从 0 开始)
                index=i
            }
        }

        // 3.注册事件
        // 3.2点击上一页
        prev.onclick = function () {
            // 如果是第一张,变成最后一张,否则 index--
            if (index == 0) {
                index = imgArr.length - 1
            }
            else {
                index--
            }
            // 图片的 src 重新赋值
            img.src = imgArr[index]
            // 上一个 li 移除样式
            document.querySelector('.dotted li.current').classList.remove('current')
            // 当前的 li 添加样式
            liList[index].classList.add('current')
        }
        
        
        // 3.注册事件
        // 3.3点击下一页
        next.onclick = function () {
            // 如果是最后一张,变成第一张,否则 index++
            if (index == imgArr.length - 1) {
                index = 0
            } else {
                index++
            }
            // 图片的 src 重新赋值
            img.src = imgArr[index]
            // 上一个 li 移除样式
            document.querySelector('.dotted li.current').classList.remove('current')
            // 当前的 li 添加样式
            liList[index].classList.add('current')
        }

        // 3.注册事件
        // 3.4每隔3秒自动轮播下一页 
        let timeID = setInterval(function () {
            next.onclick()
        }, 3000)
        
        // 3.注册事件
        // 3.5鼠标移入大盒子,停止轮播
        box.onmouseenter = function () {
            clearInterval(timeID)
        }
        
        // 3.注册事件
        // 3.6鼠标移出大盒子,继续轮播
        box.onmouseleave = function () {
            timeID = setInterval(function () {
                next.onclick()
            }, 3000)
        }
    </script>

</body>

</html>

2、简洁版,优化代码,提高用户体验

  • 排他思想样式的变化,可以抽离封装成函数
  • 鼠标移入 li 元素 可以做防抖,优化用户体验
  • 点击上一页下一页,下标的判断改成三元
  <script>
        // 0.存储图片
        let imgArr = [
            './imges/1.jpg',
            './imges/2.jpg',
            './imges/3.jpg',
            './imges/4.jpg',
            './imges/5.jpg',
            './imges/6.jpg',
            './imges/7.jpg',
            './imges/8.jpg']

        // 1.获取数据
        let prev = document.querySelector('.prev')//上一页
        let next = document.querySelector('.next')//下一页
        let liList = document.querySelectorAll('.dotted li')//小圆圈//伪数组
        let img = document.querySelector('.focus img')//获取大图
        let box = document.querySelector('.box')//为后面做铺垫,鼠标移入大盒子,停止轮播

        // 2.测试数据是否获取
        console.log(prev, next, liList, img, box)

        /* ◆◆◆封装函数 */
        let paita = function (flag) {
            document.querySelector('.dotted li.current').classList.remove('current')
            liList[flag].classList.add('current')
            img.src = imgArr[flag]
        }

        //◆全局变量,图片切换做准备(非常重要)
        let index = 0

        // 3.注册事件
        // 3.1鼠标移入小li
        for (let i = 0; i < liList.length; i++) {
            // ◆防抖第一步:声明变量存储定时器
            let timer = null
            liList[i].onmouseenter = function () {
                // ◆防抖第二步:移除上次定时器
                clearTimeout(timer)
                // ◆防抖第三步:开启本次定时器
                timer = setTimeout(() => {
                    // 调用
                    paita(i)
                    // 存储下标(不存储下标的话,每次点击上一页下一页,下标都是从 0 开始)
                    index = i
                }, 300)
            }
        }

        // 3.注册事件
        // 3.2点击上一页
        prev.onclick = function () {
            // 如果是第一张,变成最后一张,否则 index--
            index == 0 ? index = imgArr.length - 1 : index--
            // 调用
            paita(index)
        }
        
        // 3.注册事件
        // 3.3点击下一页
        next.onclick = function () {
            // 如果是最后一张,变成第一张,否则 index++
            index == imgArr.length - 1 ? index = 0 : index++
            // 调用
            paita(index)
        }

        // 3.注册事件
        // 3.4每隔3秒自动轮播下一页 
        let timeID = setInterval(function () {
            next.onclick()
        }, 3000)
        
        // 3.注册事件
        // 3.5鼠标移入大盒子,停止轮播
        box.onmouseenter = function () {
            clearInterval(timeID)
        }
        
        // 3.注册事件
        // 3.6鼠标移出大盒子,继续轮播
        box.onmouseleave = function () {
            timeID = setInterval(function () {
                next.onclick()
            }, 3000)
        }
    </script>