# HTML+CSS+JS 实现轮播时间轴

# 实现效果

02.jpg

01.jpg

# CSS 部分

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>轮播时间轴</title>
    <link rel="stylesheet" href="https://static.fontawesome.com/css/fontawesome-app.css">
    <!-- 引入字体图标 -->
    <link rel="stylesheet" href="./font/iconfont.css">
    <!-- 引入字体 -->
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400&display=swap">
    <style>
        * {
            padding: 0;
            margin: 0;
            font-family: "Source Sans Pro", sans-serif;
        }
        /* 设置 html 和 body 元素为 flex 布局,水平和垂直居中对齐,高度为 100vh,背景图大小为 cover,溢出隐藏,背景图过渡动画时间为 0.7 秒 */
        html,
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-size: cover;
            overflow: hidden;
            transition: background-image .7s ease-in-out;
        }
        /* 设置.shell 元素为相对定位,flex 布局,水平和垂直居中对齐,宽度和高度为 100%,盒模型为 border-box,背景颜色为 rgba (99, 99, 99, 0.8) */
        .shell {
            position: relative;
            display: flex;
            justify-content: center;
            align-items: center;
            width: 100%;
            height: 100%;
            box-sizing: border-box;
            background: rgba(99, 99, 99, 0.8);
        }
        /* 设置.button 元素为 flex 布局,两端对齐,宽度为 380px,绝对定位,左侧偏移量为 50%,水平居中,底部偏移量为 - 80px */
        .button {
            display: flex;
            justify-content: space-between;
            align-items: center;
            width: 380px;
            position: absolute;
            left: 50%;
            transform: translateX(-50%);
            bottom: -80px;
        }
        /* 设置.prev 和.next 元素过渡动画时间为 0.25 秒,层级为 99999,底部偏移量为 5px */
        .prev,
        .next {
            transition: transform 0.25s ease;
            z-index: 99999;
            bottom: 5px;
        }
        /* 设置.prev 和.next 元素中的 i 元素字体大小为 90px,颜色为 #fff,光标为指针,文字阴影为 0 0 10px #ffffff */
        .prev i,
        .next i {
            font-size: 90px;
            color: #fff;
            cursor: pointer;
            text-shadow: 0 0 10px #ffffff;
        }
        /* 设置.shell_body 元素宽度为 100%,缩放为 0.8 倍,上内边距为 20px,下内边距为 150px */
        .shell_body {
            width: 100%;
            transform: scale(.8);
            padding: 20px 0 150px 0;
        }
        /* 设置.shell_slider 元素为相对定位,过渡动画时间为 1 秒,背景为透明 */
        .shell_slider {
            position: relative;
            transition: transform 1s ease-in-out;
            background: transparent;
        }
        /* 设置.item 元素为相对定位,左浮动,左右外边距为 20px */
        .item {
            position: relative;
            float: left;
            margin: 0 20px;
        }
        /* 设置.frame 元素为相对定位,宽度和高度为 100%,过渡动画时间为 1 秒,3D 变换模式为保留 3D 效果 */
        .frame {
            position: relative;
            width: 100%;
            height: 100%;
            transition: transform 1s ease-in-out;
            transform-style: preserve-3d;
        }
        /* 设置.frame 元素的伪元素为绝对定位,底部偏移量为 - 16%,宽度为 100%,高度为 60px,背景颜色为 #ffffff1c,盒阴影为 0px 0px 15px 5px #ffffff1c,3D 变换为绕 X 轴旋转 90 度并向上平移 20px */
        .frame:after {
            content: "";
            position: absolute;
            bottom: -16%;
            width: 100%;
            height: 60px;
            background: #ffffff1c;
            box-shadow: 0px 0px 15px 5px #ffffff1c;
            transform: rotateX(90deg) translate3d(0px, -20px, 0px);
        }
        /* 设置.box 元素为 flex 布局,纵向排列,水平和垂直居中对齐,绝对定位,宽度和高度为 100%,边框为 4px 实心白色,透视效果为 1000px,3D 变换模式为保留 3D 效果 */
        .box {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            position: absolute;
            width: 100%;
            height: 100%;
            border: 4px solid #fff;
            perspective: 1000px;
            transform-style: preserve-3d;
        }
        /* 设置.box 元素中的 h1 和 span 元素颜色为 #fff,Z 轴平移距离为 20px */
        .box h1,
        .box span {
            color: #fff;
            transform: translateZ(20px);
        }
        /* 设置.box 元素中的 h1 元素文字阴影为 0 0 30px #1f05b4,字体大小为 100px */
        .box h1 {
            text-shadow: 0 0 30px #1f05b4;
            font-size: 100px;
        }
        /* 设置.box 元素中的 span 元素为绝对定位,底部偏移量为 20px,左右内边距为 25px,文字阴影为 0 0 10px #1f05b4 */
        .box span {
            position: absolute;
            bottom: 20px;
            padding: 0 25px;
            text-shadow: 0 0 10px #1f05b4;
        }
        /* 设置.front、.left 和.right 元素的盒阴影为 0 0 50px #ffffff,背景图大小为 cover */
        .front,
        .left,
        .right {
            box-shadow: 0 0 50px #ffffff;
            background-size: cover;
        }
        /* 设置.left 和.right 元素的顶部偏移量为 0,宽度为 60px,背面不可见 */
        .right,
        .left {
            top: 0;
            width: 60px;
            backface-visibility: hidden;
        }
        /* 设置.left 元素的左侧偏移量为 0,左边框宽度为 5px,3D 变换为向右平移 1px,Z 轴平移 - 60px,绕 Y 轴逆时针旋转 90 度,变换原点为左侧 */
        .left {
            left: 0;
            border-left-width: 5px;
            transform: translate3d(1px, 0, -60px) rotateY(-90deg);
            transform-origin: 0%;
        }
        /* 设置.right 元素的右侧偏移量为 0,右边框宽度为 5px,3D 变换为向左平移 1px,Z 轴平移 - 60px,绕 Y 轴顺时针旋转 90 度,变换原点为右侧 */
        .right {
            right: 0;
            border-right-width: 5px;
            transform: translate3d(-1px, 0, -60px) rotateY(90deg);
            transform-origin: 100%;
        }
    </style>
</head>

# HTML 部分

<body>
    <div class="shell">
        <div class="shell_body">
            <div class="button">
                <div class="prev"><i class="iconfont icon-backward_filled"></i></div>
                <div class="next"><i class="iconfont icon-forward_filled"></i></div>
            </div>
            <div class="shell_slider">
                <div class="item">
                    <div class="frame">
                        <div class="box front">
                            <h1>2014</h1>
                            <span>-In the year 2014 I reached the age of 13-</span>
                        </div>
                        <div class="box left"></div>
                        <div class="box right"> </div>
                    </div>
                </div>
                <div class="item">
                    <div class="frame">
                        <div class="box front">
                            <h1>2015</h1>
                            <span>-In the year 2015 I reached the age of 14-</span>
                        </div>
                        <div class="box left"></div>
                        <div class="box right"> </div>
                    </div>
                </div>
                <div class="item">
                    <div class="frame">
                        <div class="box front">
                            <h1>2016</h1>
                            <span>-In the year 2016 I reached the age of 15-</span>
                        </div>
                        <div class="box left"></div>
                        <div class="box right"></div>
                    </div>
                </div>
                <div class="item">
                    <div class="frame">
                        <div class="box front">
                            <h1>2017</h1>
                            <span>-In the year 2017 I reached the age of 16-</span>
                        </div>
                        <div class="box left"></div>
                        <div class="box right"> </div>
                    </div>
                </div>
                <div class="item">
                    <div class="frame">
                        <div class="box front">
                            <h1>2018</h1>
                            <span>-In the year 2018 I reached the age of 17-</span>
                        </div>
                        <div class="box left"></div>
                        <div class="box right"> </div>
                    </div>
                </div>
                <div class="item">
                    <div class="frame">
                        <div class="box front">
                            <h1>2019</h1>
                            <span>-In the year 2019 I reached the age of 18-</span>
                        </div>
                        <div class="box left"></div>
                        <div class="box right"> </div>
                    </div>
                </div>
                <div class="item">
                    <div class="frame">
                        <div class="box front">
                            <h1>2020</h1>
                            <span>-In the year 2020 I reached the age of 18-</span>
                        </div>
                        <div class="box left"></div>
                        <div class="box right"> </div>
                    </div>
                </div>
                <div class="item">
                    <div class="frame">
                        <div class="box front">
                            <h1>2021</h1>
                            <span>-In the year 2021 I reached the age of 19-</span>
                        </div>
                        <div class="box left"></div>
                        <div class="box right"> </div>
                    </div>
                </div>
                <div class="item">
                    <div class="frame">
                        <div class="box front">
                            <h1>2022</h1>
                            <span>-In the year 2022 I reached the age of 20-</span>
                        </div>
                        <div class="box left"></div>
                        <div class="box right"> </div>
                    </div>
                </div>
                <div class="item">
                    <div class="frame">
                        <div class="box front">
                            <h1>2023</h1>
                            <span>-In the year 2023 I reached the age of 21-</span>
                        </div>
                        <div class="box left"></div>
                        <div class="box right"> </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>

# JS 部分

<script>
    // 这段 JavaScript 代码的作用是实现一个图片轮播效果。首先,通过 document.getElementsByClassName ('item') 获取到所有具有 item 类名的元素,并将它们存储在 items 变量中。
    // 然后,通过一个循环遍历每个 item 元素。在循环中,首先获取当前的 item 元素,然后通过 getElementsByClassName 方法获取到该 item 下的 frame、front、left 和 right 元素,并将它们分别存储在 frame、frontBox、leftBox 和 rightBox 变量中。
    // 接下来,通过设置 frontBox、leftBox 和 rightBox 的 style.backgroundImage 属性,将背景图片设置为 'url (./img/' + (i + 1).toString ().padStart (2, '0') + '.jpg)',其中 (i + 1).toString ().padStart (2, '0') 表示将循环变量 i 加 1 后转换为字符串,并在前面补 0,以保证图片的文件名格式正确。
    // 接着,定义了一个立即执行函数,并在函数内部进行了一些操作。首先,通过 document.getElementsByClassName ('shell')[0] 获取到具有 shell 类名的元素,并将其存储在 shell 变量中。然后,通过 shell.getElementsByClassName 方法获取到该 shell 元素下的 shell_slider、item、prev 和 next 元素,并将它们分别存储在 slider、items、prevBtn 和 nextBtn 变量中。
    // 接下来,定义了一些变量,包括 width、height、totalWidth、margin、currIndex、interval 和 intervalTime。width 和 height 分别表示每个 item 的宽度和高度,totalWidth 表示所有 item 的总宽度,margin 表示 item 的外边距,currIndex 表示当前显示的 item 的索引,interval 表示定时器的 ID,intervalTime 表示定时器的时间间隔。
    // 然后,定义了 init 函数,该函数用于初始化一些操作。在该函数中,首先调用 resize 函数调整大小,然后调用 move 函数将显示的 item 移动到中间位置,接着调用 bindEvents 函数绑定事件,最后调用 timer 函数启动定时器。
    // 接着,定义了 resize 函数,该函数用于在窗口大小变化时调整大小。在该函数中,首先计算出新的 width 和 height,然后根据计算结果设置 slider 的宽度,以及每个 item 的宽度和高度。
    // 接下来,定义了 bindEvents 函数,该函数用于绑定事件。在该函数中,首先绑定了窗口大小变化时调用 resize 函数的事件,然后绑定了点击 prev 按钮和 next 按钮时调用 prev 函数和 next 函数的事件。
    // 最后,在立即执行函数的末尾,调用了 init 函数来初始化页面,并定义了 move、timer、prev 和 next 函数。其中,move 函数用于移动 shell 到指定的 item,timer 函数用于启动定时器,prev 函数用于切换到上一个 item,next 函数用于切换到下一个 item。
    // 获取所有的 item 元素
    var items = document.getElementsByClassName('item');
    // 循环遍历每个 item
    for (var i = 0; i < items.length; i++) {
        // 获取当前 item
        var item = items[i];
        var frame = item.getElementsByClassName('frame')[0];
        var frontBox = frame.getElementsByClassName('front')[0];
        var leftBox = frame.getElementsByClassName('left')[0];
        var rightBox = frame.getElementsByClassName('right')[0];
        // 设置背景图片
        frontBox.style.backgroundImage = 'url(./img/' + (i + 1).toString().padStart(2, '0') + '.jpg)';
        leftBox.style.backgroundImage = 'url(./img/' + (i + 1).toString().padStart(2, '0') + '.jpg)';
        rightBox.style.backgroundImage = 'url(./img/' + (i + 1).toString().padStart(2, '0') + '.jpg)';
    }
    (function () {
        "use strict";
        var shell = document.getElementsByClassName('shell')[0];
        var slider = shell.getElementsByClassName('shell_slider')[0];
        var items = shell.getElementsByClassName('item');
        var prevBtn = shell.getElementsByClassName('prev')[0];
        var nextBtn = shell.getElementsByClassName('next')[0];
        // 定义变量
        var width, height, totalWidth, margin = 20,
            currIndex = 0,
            interval, intervalTime = 3000;
        function init() {
            // 初始化函数
            resize();
            move(Math.floor(items.length / 2));
            bindEvents();
            timer();
        }
        function resize() {
            // 窗口大小变化时调整大小
            width = Math.max(window.innerWidth * .20, 275);
            height = window.innerHeight * .5;
            totalWidth = width * items.length;
            // 设置 slider 宽度
            slider.style.width = totalWidth + "px";
            // 设置每个 item 的宽度和高度
            for (var i = 0; i < items.length; i++) {
                let item = items[i];
                item.style.width = (width - (margin * 2)) + "px";
                item.style.height = height + "px";
            }
        }
        function bindEvents() {
            // 窗口大小变化时调整大小
            window.onresize = resize;
            // 点击 prev 按钮切换 item
            prevBtn.addEventListener('click', () => { prev(); });
            nextBtn.addEventListener('click', () => { next(); });
        }
        init();
        function move(index) {
            // 移动 shell 到指定的 item
            if (index < 1) index = items.length;
            if (index > items.length) index = 1;
            currIndex = index;
            // 遍历所有 item
            for (var i = 0; i < items.length; i++) {
                let item = items[i],
                    box = item.getElementsByClassName('frame')[0];
                if (i == (index - 1)) {
                    // 当前 item 添加 active 类并设置 3D 效果
                    item.classList.add('item--active');
                    box.style.transform = "perspective(1200px)";
                } else {
                    // 其他 item 移除 active 类并设置 3D 效果
                    item.classList.remove('item--active');
                    box.style.transform = "perspective(1200px) rotateY(" + (i < (index - 1) ? 40 : -40) + "deg)";
                }
            }
            // 移动 slider
            slider.style.transform = "translate3d(" + ((index * -width) + (width / 2) + window.innerWidth / 2) + "px, 0, 0)";
            // 设置 body 背景图片
            var frontBox = items[index - 1].getElementsByClassName('front')[0];
            document.body.style.backgroundImage = frontBox.style.backgroundImage;
        }
        function timer() {
            // 定时器,自动切换 shell
            clearInterval(interval);
            interval = setInterval(() => {
                move(++currIndex);
            }, intervalTime);
        }
        // 切换 item
        function prev() {
            move(--currIndex);
            timer();
        }
        function next() {
            move(++currIndex);
            timer();
        }
    })();
</script>

在 VScode 中新建.html 文件将以上代码段依次粘贴进去就完成了!不要忘记把 img 文件夹放在同级根目录下,使用到的图片都要以 01.jpg,02.jpg……10.jpg 形式命名哦,图片分辨率建议 1200*560px~