JavaScript 系列三:練習7

carousel 輪播元件

by applelily

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JavaScript 系列三:練習7 ── carousel 輪播元件</title>
    <link rel="stylesheet" href="./js_carousel.css">
</head>
<body>
<!-- image 
https://images.unsplash.com/photo-1606800052052-a08af7148866?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D

https://images.unsplash.com/photo-1511795409834-ef04bbd61622?q=80&w=1469&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D

https://images.unsplash.com/photo-1583155248780-93f25aaabc1c?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D

https://images.unsplash.com/photo-1600038938045-b5fadbc55083?q=80&w=987&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D

https://images.unsplash.com/photo-1506355639690-a1f2a100689e?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D

-->
<section class="main-carousel">
    <div class="carousel-inner">
        <div class="slide">
            <img src="https://images.unsplash.com/photo-1606800052052-a08af7148866?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="image 1">
        </div>
        <div class="slide">
            <img src="https://images.unsplash.com/photo-1511795409834-ef04bbd61622?q=80&w=1469&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="image 2">
        </div>
        <div class="slide">
            <img src="https://images.unsplash.com/photo-1583155248780-93f25aaabc1c?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="image 3">
        </div>
        <div class="slide">
            <img...

CSS

*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
/* 整個carousel區塊 */
.main-carousel{
    position: relative;
    width:100%;
    height: 600px;
    overflow: hidden;
    border-radius: 30px;
    box-shadow: rgba(0, 0, 0, 0.25) 0px 54px 55px, rgba(0, 0, 0, 0.12) 0px -12px 30px, rgba(0, 0, 0, 0.12) 0px 4px 6px, rgba(0, 0, 0, 0.17) 0px 12px 13px, rgba(0, 0, 0, 0.09) 0px -3px 5px;
}
/* 圖片顯示區域 */
.main-carousel .carousel-inner{
    width: 100%;
    height: 100%;

}

/* 所有圖片的 div,設定為絕對位置讓圖片層疊 */
.main-carousel .carousel-inner .slide{
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    transition: left .5s;
}

/* 圖片本身 */
.main-carousel .carousel-inner .slide > img{
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.left-slide-btn, .right-slide-btn {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background-color: rgba(0, 0, 0, 0.5);
    border: none;
    color: white;
    font-size: 2rem;
    padding: 10px;
    cursor: pointer;
    z-index: 10;
    outline: none;
}

.left-slide-btn {
    left: 10px;
}

.right-slide-btn {
    right: 10px;
}


.slide-dots {
    position: absolute;
    bottom: 30px;
    width: 100%;
    text-align: center;
    z-index: 20;  /* Ensure dots are above slides and buttons */
}
.slide-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    background-color: gray;
    border-radius: 50%;
    margin: 5px;
    cursor: pointer;
}
.active-dot {
    background-color: #1616ed;
}

JavaScript

const carsouselInner = document.querySelector('.carousel-inner');
const slides = carsouselInner.children;
const imgCount = slides.length;
const slides_position = [];
const slideDots = document.querySelector('.slide-dots');

// Generate dots
for (let i = 0; i < imgCount; i++) {
    const dot = document.createElement('span');
    dot.classList.add('slide-dot');
    dot.dataset.index = i;
    slideDots.appendChild(dot);
}

// Set the active dot
function setActiveDot(index) {
    const dots = document.querySelectorAll('.slide-dot');
    dots.forEach(dot => dot.classList.remove('active-dot'));
    dots[index].classList.add('active-dot');
}

// Initialize the carousel
function showDefault() {
    for (let i = 0; i < imgCount; i++) {
        slides[i].style.left = i * 100 + `%`;
        slides_position[i] = i * 100;
    }
    setActiveDot(0);
}

function showDefault_left() {
    for (let i = 0; i < imgCount; i++) {
        slides[i].style.left = slides_position[i] + `%`;
    }
    setActiveDot(currentIndex);
}

function skipSlide(targetSlide, dist) {
    slides_position.forEach((x, i, positions) => {
        positions[i] = x - dist;
        slides[i].style.left = `${positions[i]}%`;
    });
    setActiveDot(targetSlide);
}

const rightSlideBtn = document.querySelector('.right-slide-btn');
var currentIndex = 0;
rightSlideBtn.addEventListener('click', function () {
    let dist = 100;
    if (currentIndex < (imgCount - 1)) {
        currentIndex += 1;
        skipSlide(currentIndex, dist);
    } else {
        currentIndex = 0;
        showDefault();
    }
});

const leftSlideBtn = document.querySelector('.left-slide-btn');
leftSlideBtn.addEventListener('click', function () {
    let dist = 100;
    if (currentIndex === 0) {
        currentIndex = imgCount - 1;
        showDefault_left();
        skipSlide(currentIndex, dist * (imgCount - 1));
    } else {
        currentIndex -= 1;
        skipSlide(currentIndex, -dist);
    }
});

// Add click event to...