前端轮播图carousel案例(带详细注释)

文章目录

carousel.html

html 复制代码
<!DOCTYPE html> <!-- 声明文档类型为HTML5 -->
<html lang="zh-CN"> <!-- 开始HTML文档,设置语言为中文 -->

<head> <!-- 头部区域,包含元数据和资源引用 -->
    <meta charset="UTF-8"> <!-- 设置字符编码为UTF-8,支持中文等多语言 -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- 设置视口,使页面在移动设备上正确缩放 -->
    <title>响应式轮播图</title> <!-- 设置页面标题,显示在浏览器标签上 -->
    <link rel="stylesheet" href="carousel.css"> <!-- 引入外部CSS样式表 -->
</head>

<body> <!-- 网页主体内容区域 -->
    <div class="carousel-container"> <!-- 轮播图外层容器,控制整体宽度和居中 -->
        <div class="carousel-wrapper"> <!-- 轮播图包装器,设置相对定位和溢出隐藏 -->
            <div class="carousel-slides"> <!-- 轮播图幻灯片区域,包含所有轮播图片 -->
                <div class="carousel-slide active"> <!-- 第一张幻灯片,设置为激活状态(默认显示) -->
                    <img src="https://picsum.photos/800/400?random=1" alt="幻灯片1"> <!-- 图片元素,使用随机图片服务,alt属性提供替代文本 -->
                </div>
                <div class="carousel-slide"> <!-- 第二张幻灯片,初始状态为隐藏 -->
                    <img src="https://picsum.photos/800/400?random=2" alt="幻灯片2"> <!-- 第二张随机图片 -->
                </div>
                <div class="carousel-slide"> <!-- 第三张幻灯片,初始状态为隐藏 -->
                    <img src="https://picsum.photos/800/400?random=3" alt="幻灯片3"> <!-- 第三张随机图片 -->
                </div>
                <div class="carousel-slide"> <!-- 第四张幻灯片,初始状态为隐藏 -->
                    <img src="https://picsum.photos/800/400?random=4" alt="幻灯片4"> <!-- 第四张随机图片 -->
                </div>
            </div>

            <!-- 导航按钮 --> <!-- 注释说明下面是导航按钮区域 -->
            <button class="carousel-button prev">&lt;</button> <!-- 上一张按钮,使用&lt;显示<符号 -->
            <button class="carousel-button next">&gt;</button> <!-- 下一张按钮,使用&gt;显示>符号 -->

            <!-- 指示器点 --> <!-- 注释说明下面是指示器点区域 -->
            <div class="carousel-indicators"> <!-- 指示器容器,显示当前幻灯片位置 -->
                <span class="indicator active" data-index="0"></span> <!-- 第一个指示器点,初始状态为激活,对应第一张幻灯片 -->
                <span class="indicator" data-index="1"></span> <!-- 第二个指示器点,对应第二张幻灯片 -->
                <span class="indicator" data-index="2"></span> <!-- 第三个指示器点,对应第三张幻灯片 -->
                <span class="indicator" data-index="3"></span> <!-- 第四个指示器点,对应第四张幻灯片 -->
            </div>
        </div>
    </div>

    <script src="carousel.js"></script> <!-- 引入外部JavaScript文件,处理轮播图交互逻辑 -->
</body>

</html> <!-- 结束HTML文档 -->

carousel.css

css 复制代码
* { /* 通用选择器,应用于页面中的所有元素 */
    margin: 0; /* 移除所有元素的外边距 */
    padding: 0; /* 移除所有元素的内边距 */
    box-sizing: border-box; /* 将盒模型设置为border-box,使元素的宽高包含padding和border */
}

body { /* 应用于网页的body元素 */
    font-family: 'Arial', sans-serif; /* 设置字体为Arial,如果不可用则使用系统默认无衬线字体 */
    display: flex; /* 使用弹性布局 */
    justify-content: center; /* 水平居中对齐 */
    align-items: center; /* 垂直居中对齐 */
    min-height: 100vh; /* 最小高度为视口高度的100% */
    background-color: #f5f5f5; /* 设置浅灰色背景 */
}

.carousel-container { /* 轮播图最外层容器 */
    width: 100%; /* 宽度为父元素的100% */
    max-width: 800px; /* 最大宽度为800px,防止在大屏幕上过宽 */
    margin: 0 auto; /* 上下边距为0,左右自动(居中) */
}

.carousel-wrapper { /* 轮播图包装器 */
    position: relative; /* 设置相对定位,作为内部绝对定位元素的参考 */
    overflow: hidden; /* 隐藏超出容器的内容 */
    border-radius: 10px; /* 设置圆角为10px */
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); /* 添加阴影效果,营造立体感 */
}

.carousel-slides { /* 包含所有幻灯片的容器 */
    display: flex; /* 使用弹性布局,使幻灯片水平排列 */
    transition: transform 0.5s ease; /* 添加过渡效果,使移动平滑 */
}

.carousel-slide { /* 单个幻灯片样式 */
    min-width: 100%; /* 最小宽度为父容器的100%,确保幻灯片占满整个容器 */
    opacity: 0; /* 初始透明度为0(隐藏状态) */
    transition: opacity 0.5s ease; /* 添加透明度过渡效果,使切换平滑 */
    position: absolute; /* 绝对定位,使幻灯片可以叠放 */
    top: 0; /* 距顶部0px */
    left: 0; /* 距左侧0px */
}

.carousel-slide.active { /* 当前显示的激活幻灯片 */
    opacity: 1; /* 透明度为1(完全显示) */
    position: relative; /* 改为相对定位,使其占据空间,撑开容器 */
}

.carousel-slide img { /* 幻灯片中的图片 */
    width: 100%; /* 宽度为父元素的100% */
    height: auto; /* 高度自动,保持图片原始比例 */
    display: block; /* 设置为块级元素,避免底部间隙 */
}

.carousel-button { /* 导航按钮的基本样式 */
    position: absolute; /* 绝对定位,相对于.carousel-wrapper */
    top: 50%; /* 从顶部偏移50% */
    transform: translateY(-50%); /* 向上平移自身高度的50%,实现垂直居中 */
    width: 40px; /* 宽度为40px */
    height: 40px; /* 高度为40px */
    border-radius: 50%; /* 设置为圆形 */
    background-color: rgba(255, 255, 255, 0.7); /* 半透明白色背景 */
    border: none; /* 移除边框 */
    cursor: pointer; /* 鼠标悬停时显示手型光标 */
    font-size: 20px; /* 字体大小为20px */
    font-weight: bold; /* 字体加粗 */
    color: #333; /* 文字颜色为深灰色 */
    display: flex; /* 使用弹性布局 */
    justify-content: center; /* 水平居中 */
    align-items: center; /* 垂直居中 */
    transition: all 0.3s ease; /* 添加过渡效果 */
    z-index: 10; /* 设置层级,确保按钮显示在幻灯片上方 */
}

.carousel-button:hover { /* 鼠标悬停在按钮上时的样式 */
    background-color: rgba(255, 255, 255, 0.9); /* 增加背景不透明度 */
}

.carousel-button.prev { /* 上一张按钮的位置 */
    left: 10px; /* 距左侧10px */
}

.carousel-button.next { /* 下一张按钮的位置 */
    right: 10px; /* 距右侧10px */
}

.carousel-indicators { /* 指示器点容器 */
    position: absolute; /* 绝对定位 */
    bottom: 15px; /* 距底部15px */
    left: 50%; /* 距左侧50% */
    transform: translateX(-50%); /* 向左平移自身宽度的50%,实现水平居中 */
    display: flex; /* 使用弹性布局,使指示器点水平排列 */
    gap: 10px; /* 指示器点之间的间距为10px */
    z-index: 10; /* 设置层级,确保指示器显示在幻灯片上方 */
}

.indicator { /* 单个指示器点的样式 */
    width: 12px; /* 宽度为12px */
    height: 12px; /* 高度为12px */
    border-radius: 50%; /* 设置为圆形 */
    background-color: rgba(255, 255, 255, 0.5); /* 半透明白色背景 */
    cursor: pointer; /* 鼠标悬停时显示手型光标 */
    transition: all 0.3s ease; /* 添加过渡效果 */
}

.indicator.active { /* 当前激活的指示器点 */
    background-color: white; /* 背景色为纯白色 */
    transform: scale(1.2); /* 放大到原来的1.2倍 */
}

/* 响应式设计 */ /* 针对不同屏幕尺寸的样式调整 */
@media (max-width: 768px) { /* 当屏幕宽度小于等于768px时应用以下样式 */
    .carousel-button { /* 在小屏幕上调整按钮大小 */
        width: 30px; /* 减小宽度为30px */
        height: 30px; /* 减小高度为30px */
        font-size: 16px; /* 减小字体大小为16px */
    }

    .indicator { /* 在小屏幕上调整指示器点大小 */
        width: 10px; /* 减小宽度为10px */
        height: 10px; /* 减小高度为10px */
    }
}

carousel.js

javascript 复制代码
document.addEventListener('DOMContentLoaded', function () { // 当DOM内容加载完成后执行函数
    // 获取所有必要的元素
    const slides = document.querySelectorAll('.carousel-slide'); // 获取所有幻灯片元素
    const indicators = document.querySelectorAll('.indicator'); // 获取所有指示器点
    const prevButton = document.querySelector('.carousel-button.prev'); // 获取上一张按钮
    const nextButton = document.querySelector('.carousel-button.next'); // 获取下一张按钮

    let currentIndex = 0; // 当前显示的幻灯片索引,初始为0(第一张)
    let interval; // 存储自动轮播定时器的变量
    const autoPlayDelay = 5000; // 自动轮播间隔时间,设置为5000毫秒(5秒)

    // 初始化自动轮播
    startAutoPlay(); // 页面加载后立即开始自动轮播

    // 设置当前激活的幻灯片
    function setActiveSlide(index) { // 定义切换幻灯片的函数,接收目标索引参数
        // 移除所有激活状态
        slides.forEach(slide => slide.classList.remove('active')); // 移除所有幻灯片的active类
        indicators.forEach(indicator => indicator.classList.remove('active')); // 移除所有指示器点的active类

        // 设置新的激活状态
        slides[index].classList.add('active'); // 为目标幻灯片添加active类
        indicators[index].classList.add('active'); // 为对应的指示器点添加active类

        currentIndex = index; // 更新当前索引变量
    }

    // 前进到下一张幻灯片
    function nextSlide() { // 定义切换到下一张幻灯片的函数
        let newIndex = currentIndex + 1; // 计算下一张幻灯片的索引
        if (newIndex >= slides.length) { // 如果索引超出范围
            newIndex = 0; // 循环回到第一张
        }
        setActiveSlide(newIndex); // 调用setActiveSlide函数切换到新索引的幻灯片
    }

    // 后退到上一张幻灯片
    function prevSlide() { // 定义切换到上一张幻灯片的函数
        let newIndex = currentIndex - 1; // 计算上一张幻灯片的索引
        if (newIndex < 0) { // 如果索引小于0
            newIndex = slides.length - 1; // 循环到最后一张
        }
        setActiveSlide(newIndex); // 调用setActiveSlide函数切换到新索引的幻灯片
    }

    // 开始自动轮播
    function startAutoPlay() { // 定义开始自动轮播的函数
        stopAutoPlay(); // 先停止可能存在的定时器,避免多个定时器同时运行
        interval = setInterval(nextSlide, autoPlayDelay); // 设置定时器,每隔autoPlayDelay毫秒自动调用nextSlide函数
    }

    // 停止自动轮播
    function stopAutoPlay() { // 定义停止自动轮播的函数
        if (interval) { // 如果定时器存在
            clearInterval(interval); // 清除定时器
        }
    }

    // 按钮点击事件
    nextButton.addEventListener('click', function () { // 为下一张按钮添加点击事件监听器
        nextSlide(); // 调用nextSlide函数切换到下一张
        startAutoPlay(); // 重置自动轮播计时器,避免点击后立即自动切换造成的不良体验
    });

    prevButton.addEventListener('click', function () { // 为上一张按钮添加点击事件监听器
        prevSlide(); // 调用prevSlide函数切换到上一张
        startAutoPlay(); // 重置自动轮播计时器
    });

    // 指示器点击事件
    indicators.forEach((indicator, index) => { // 为每个指示器点添加点击事件
        indicator.addEventListener('click', function () { // 添加点击事件监听器
            setActiveSlide(index); // 调用setActiveSlide函数切换到对应索引的幻灯片
            startAutoPlay(); // 重置自动轮播计时器
        });
    });

    // 当鼠标悬停在轮播图上时,暂停自动轮播
    const carouselWrapper = document.querySelector('.carousel-wrapper'); // 获取轮播图容器元素
    carouselWrapper.addEventListener('mouseenter', stopAutoPlay); // 鼠标进入时停止自动轮播
    carouselWrapper.addEventListener('mouseleave', startAutoPlay); // 鼠标离开时恢复自动轮播

    // 触摸事件支持(适用于移动设备)
    let touchStartX = 0; // 存储触摸开始位置的X坐标
    let touchEndX = 0; // 存储触摸结束位置的X坐标

    carouselWrapper.addEventListener('touchstart', function (e) { // 添加触摸开始事件监听器
        touchStartX = e.changedTouches[0].screenX; // 记录第一个触摸点的X坐标
        stopAutoPlay(); // 停止自动轮播
    }, { passive: true }); // 使用passive: true提高性能,表示不会调用preventDefault()

    carouselWrapper.addEventListener('touchend', function (e) { // 添加触摸结束事件监听器
        touchEndX = e.changedTouches[0].screenX; // 记录触摸结束时的X坐标
        handleSwipe(); // 处理滑动事件
        startAutoPlay(); // 恢复自动轮播
    }, { passive: true }); // 使用passive: true提高性能

    function handleSwipe() { // 定义处理滑动的函数
        const swipeThreshold = 50; // 滑动阈值,需要超过这个距离才判定为有效滑动
        if (touchEndX < touchStartX - swipeThreshold) { // 如果向左滑动超过阈值
            // 向左滑动 -> 下一张
            nextSlide(); // 切换到下一张幻灯片
        } else if (touchEndX > touchStartX + swipeThreshold) { // 如果向右滑动超过阈值
            // 向右滑动 -> 上一张
            prevSlide(); // 切换到上一张幻灯片
        }
    }
});

效果

ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍

ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ        ‌‍ᅟᅠ

相关推荐
C_V_Better18 分钟前
浏览器缓存机制:JavaScript 文件缓存导致 404 错误的解决方案
开发语言·前端·javascript·缓存
小救星小杜、21 分钟前
a = b &&c 的含义
开发语言·前端·javascript
uhakadotcom22 分钟前
Babylon.js:轻松打造Web 3D体验
前端·javascript·面试
parade岁月24 分钟前
告别代码质量隐患:Husky 生态工具链在前端工程化中的实战应用
前端·javascript
小成C24 分钟前
为什么会演化出RSC,SSR和RSC关系大解密
前端·react.js
过期的H2O226 分钟前
【H2O2 | 软件开发】Axios发送Http请求
前端·http·axios·交互
bug总结31 分钟前
vue3 public下引入图片路径打包后线上不显示问题解决
前端·javascript·vue.js
悠然青年帅34 分钟前
基于Vue+Canvas实现的画板绘画以及保存功能
前端
screct_demo37 分钟前
详细讲一下 Webpack 主要生命周期钩子流程(重难点)
前端·webpack·node.js
庸俗今天不摸鱼1 小时前
【万字总结】构建现代Web应用的全方位性能优化体系学习指南(一)
前端·性能优化·cdn