HTML+CSS+JavaScript实现轮播图

功能需求

左右按钮显示。
点击右侧按钮一次,图片往左播放一张,以此类推, 左侧按钮同理。
图片播放的同时,下面的焦点一起变化。
点击焦点,可以播放对应的图片。
鼠标不经过轮播图, 轮播图也会自动播放图片。
鼠标经过轮播图模块的时候, 自动播放会停止。

HTML部分

 <div class="banner">
        <!-- 放置所有轮播图的盒子 -->
        <ul class="img_box">
            <li style="background-color: burlywood;">1</li>
            <li style="background-color: royalblue;">2</li>
            <li style="background-color: greenyellow;">3</li>
            <li style="background-color: pink;">4</li>
            <li style="background-color: turquoise;">5</li>
        </ul>
        <!-- 放置焦点的盒子 -->
        <ol class="focus">
            <!-- <li class="active"></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li> -->
        </ol>
        <!-- 左右按钮 -->
        <div class="left">&lt;</div>
        <div class="right">&gt;</div>
    </div>
    <script src="../util.js"></script>  //外部引入JS文件
    <script src="./index.js"></script>  //外部引入JS文件

CSS部分

   <style>
        * {
            padding: 0;
            margin: 0;
        }

        .banner {
            width: 600px;
            height: 400px;
            border: 5px solid black;
            margin: 200px auto;
            overflow: hidden;
            position: relative;
        }

        .banner .img_box {
            width: 500%;
            height: 100%;
            list-style: none;
            display: flex;
            position: absolute;
            left: 0px;
        }

        .banner .img_box li {
            width: 600px;
            height: 100%;
            font-size: 50px;
            text-align: center;
            line-height: 400px;
        }

        .banner .focus {
            width: 200px;
            height: 30px;
            background-color: white;
            position: absolute;
            left: 50%;
            transform: translateX(-50%);
            bottom: 30px;
            border-radius: 20px;
            display: flex;
            justify-content: space-evenly;
            align-items: center;
            list-style: none;
        }

        .banner .focus li {
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background-color: rosybrown;
            cursor: pointer;
        }

        .banner .focus .active {
            background-color: red;
        }

        .left,
        .right {
            position: absolute;
            transform: translateY(-50%);
            font-size: 50px;
            color: white;
            top: 50%;
            cursor: pointer;
        }

        .left {
            left: 30px;
        }

        .right {
            right: 30px;
        }
    </style>

JS部分

index.js

<script>
 // 0. 获取元素
const imgBox = document.querySelector(".img_box");
const banner = document.querySelector(".banner");
const focus = document.querySelector(".focus");

// 0. 准备变量
const bannerWidth = parseInt(window.getComputedStyle(banner).width);
let index = 1; // 记录当前轮播在第几页, 默认在第一页
let timer = 0; // 记录定时器 ID, 后续方便关闭定时器
let flag = true; // 开关

// 1. 根据轮播图效果 调整 页面结构
function copyEle() {
    // 将ul开头和结尾, 放两张假图

    // 1.1 复制出ul内部第一个元素节点与最后一个元素节点
    const firstEle = imgBox.firstElementChild.cloneNode(true);
    const lastEle = imgBox.lastElementChild.cloneNode(true);

    // 1.2 将第一个图插入父级末尾, 当作一个假图
    imgBox.appendChild(firstEle);
    // 1.3 将最后一个图插入到父级开头, 当作一个假图
    imgBox.insertBefore(lastEle, imgBox.firstElementChild);

    // 1.4 处理 ul 的宽度 === 内部所有 li的数量 * 可视区域的宽度
    imgBox.style.width = imgBox.children.length * bannerWidth + "px";

    // 1.5 处理 ul 的定位
    imgBox.style.left = -(index * bannerWidth) + "px";
}
copyEle();

// 2. 根据 图片数量, 动态生成 焦点
function setFocus() {
    // 现在图片有两张 假图, 所以不需要考虑假图, 直接减2即可
    const imgBoxLength = imgBox.children.length - 2;
    for (let i = 0; i < imgBoxLength; i++) {
        // 动态生成 li
        let newLi = document.createElement("li");

        newLi.classList.add("new_li_item");
        newLi.dataset.id = i;

        if (i == 0) {
            newLi.classList.add("active");
        }
        focus.appendChild(newLi);
    }
}
setFocus();

// 3. 自动轮播
function autoPlay() {
    /**
     *  当前在 第 1 个 真图 -600px
     *  当前在 第 2 个 真图 -1200px
     *  当前在 第 3 个 真图 -1800px
     *  当前在 第 x 个 真图 -(x * 视口宽度)px
     */
    timer = setInterval(function () {
        index++;
        move(imgBox, { left: -(index * bannerWidth) }, moveEnd);
    }, 2000);
}
// autoPlay();

// 4. 拦截轮播图, 让其滚动播放
function moveEnd() {
    // 4.1 判断当前滚动到最后一张假图的时候, 让其滚动到 第一张真图
    if (index == imgBox.children.length - 1) {
        index = 1;
        imgBox.style.left = -(index * bannerWidth) + "px";
    }

    // 4.2 判断当前滚动到第一张真图的时候, 让其滚动到 最后一张真图
    if (index == 0) {
        index = imgBox.children.length - 2;
        imgBox.style.left = -(index * bannerWidth) + "px";
    }

    // 4.3 让焦点跟随
    for (let i = 0; i < focus.children.length; i++) {
        focus.children[i].classList.remove("active");
    }
    focus.children[index - 1].classList.add("active");

    flag = true; // 运动函数执行结束, 将开关打开
}

// 5. 鼠标移入移出事件
function mouseOut() {
    // 5.1 鼠标移入 banner 结束自动轮播
    banner.onmouseover = () => clearInterval(timer);

    // 5.2 鼠标移出时, 自动轮播
    banner.onmouseout = () => autoPlay();
}
mouseOut();

// 6. 鼠标点击事件
function clickBtn() {
    banner.onclick = function (e) {
        if (e.target.className == "right") {
            // if (flag == false) return
            if (!flag) return;
            flag = false; // 运动函数开始前, 关闭开关, 直到运动函数结束时打开开关
            index++;
            move(imgBox, { left: -(index * bannerWidth) }, moveEnd);
        }
        if (e.target.className == "left") {
            if (!flag) return;
            flag = false; // 运动函数开始前, 关闭开关, 直到运动函数结束时打开开关
            index--;
            move(imgBox, { left: -(index * bannerWidth) }, moveEnd);
        }
        if (e.target.className == "new_li_item") {
            if (!flag) return;
            flag = false; // 运动函数开始前, 关闭开关, 直到运动函数结束时打开开关
            index = e.target.dataset.id - 0 + 1;
            move(imgBox, { left: -(index * bannerWidth) }, moveEnd);
        }
    };
}
clickBtn();

/**
 *  7. 页面关闭抖动
 *
 *      当页面关闭时(最小化)时, 此时 DOM 不会在发生变化
 *
 *      但是我们的代码不会停止, 也就是定时器会一直执行
 *
 *      当我们再次打开页面时, 此时 DOM的真实数据, 与代码的数据已经不同
 *
 *
 *  解决:
 *          在页面关闭, 停止定时器
 *          再次打开页面时, 开启定时器
 */
document.onvisibilitychange = function () {
    if (document.visibilityState == "hidden") {
        clearInterval(timer);
    }
    if (document.visibilityState == "visible") {
        autoPlay();
    }
};
</script>

util.js

<script>
 function move(ele, options, fn = () => {}) {
    let num = 0;
    for (let key in options) {
        const type = key;
        let target = options[key];

        if (type == "opacity") {
            target *= 100;
        }
        num++;
        const timer = setInterval(function () {
            let count;
            if (type == "opacity") {
                count = window.getComputedStyle(ele)[type] * 100;
            } else {
                count = parseInt(window.getComputedStyle(ele)[type]);
            }

            let des = (target - count) / 10;
            des = des > 0 ? Math.ceil(des) : Math.floor(des);

            if (target === count) {
                num--;

                if (num == 0) {
                    fn();
                }

                clearInterval(timer);
            } else {
                if (type == "opacity") {
                    ele.style[type] = (count + des) / 100;
                } else {
                    ele.style[type] = count + des + "px";
                }
            }
        }, 20);
    }
}
</script>
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

兰de宝贝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值