效果演示

原生Js实现轮播图

HTML代码

<div class="container-slider">

    <!-- Slider Container with images...    -->
    <div class="slides"></div>

    <!--    Previous Button    -->
    <button class="btn-slide prev">
        <img src="https://imgur.com/SUyRJqI.png" alt="prevBtn" />
    </button>

    <!--    Next Button    -->
    <button class="btn-slide next">
        <img src=" https://imgur.com/M6rDsRR.png" alt="nextBtn" />
    </button>

    <!--    Container for dots    -->
    <div class="container-dots"></div>
</div>
有一个类为.container-slider的外部div。它有四个独立的子级。 .slides:包含图片,但HTML中没有添加,我们将使用JS动态添加。 .btn-slide:在父容器(.container-slider)中有两个按钮,一个用于下一张图片(.next),另一个用于上一张图片(.prev)。 .container-dots:这是我们还没有添加的.dot的容器。它将与图像一样由JS完成。

现在你对我们要做什么应该已经有了一个大概的了解。接下来进入CSS。

CSS代码

* {
    margin: 0;
    padding: 0;
}

body {
    background: azure;
    min-height: 100vh;
    padding: 0 25px;
}

/* Main Wrapper Container */
.container-slider {
    position: relative;
    max-width: 700px;
    width: 100%;
    height: 400px;
    border-radius: 20px;
    box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
    overflow: hidden;
}

/* Slider Container which contains images */
.slides {
    position: relative;
    width: 100%;
    height: 100%;
}

/* Default Image Properties */
.slides img {
    position: absolute;
    width: 50px;
    height: 50px;
    object-fit: cover;
    object-position: center;
    opacity: 0;
    transform: scale(0);
    transition: all 0.5s ease-in-out;
    transition-delay: 500ms;
}

/* Active Image or Current image to display */
.slides > img[data-active] {
    opacity: 1;
    transform: scale(1);
    transition-delay: 0ms;
    width: 100%;
    height: 100%;
    z-index: 10;
}

/* Image Slider Next And Previous Buttons */
.btn-slide {
    position: absolute;
    background: #f1f1f1;
    width: 40px;
    height: 40px;
    padding: 10px;
    border-radius: 50%;
    opacity: 0;
    border: 1px solid rgba(34, 34, 34, 0.287);
    transition: opacity 300ms ease-in-out;
    cursor: pointer;
    overflow: hidden;
    z-index: 10;
}

.btn-slide > img {
    width: 100%;
}

/* Show Buttons when user hover on the slider Container */
.container-slider:hover > .btn-slide {
    opacity: 1;
}

/* Previous and Next Button Position Absolute */
.prev,
.next {
    top: 50%;
    transform: translateY(-60%);
}

.prev {
    left: 20px;
}
.next {
    right: 20px;
}

/* Bottom Dots Container    */
.container-dots {
    position: absolute;
    bottom: 20px;
    width: 100%;
    display: flex;
    justify-content: center;
    z-index: 10;
}

/* Sigle Dot style */
.dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    border: 3px solid #f1f1f1;
    margin: 0 5px;
    background: #f1f1f1;
    cursor: pointer;
    transition: background-color 500ms ease-in-out;
}

/* Change the color of bg when user hover on it. */
.dot:hover {
    opacity: 0.9;
    background: rgb(32, 32, 32);
}

/* Current or active dot */
.dot[data-active="true"] {
    background: rgb(32, 32, 32);
}

CSS中的所有内容都是不言自明的,所以就不用我多说了。

JavaScript代码

这部分就有趣了。首先,我们需要导入两个容器,.Slides和.Container-dots。

const slides = document.querySelector(".slides");
const containerDots = document.querySelector(".container-dots");

然后将图片添加到.slides容器中。我们还需要一个全局计数器或全局索引来跟踪当前正在显示的图片。

// 全局索引,用来跟踪当前显示的图片
var slideIndex = 1;

// 需要显示的图片池数组
const images = [
    { src: "https://rb.gy/ohx0bd" },
    { src: "https://rb.gy/gggxy8" },
    { src: "https://rb.gy/z2a0fy" },
    { src: "https://rb.gy/nsefjh" },
    { src: "https://rb.gy/dssu2a" }
];

现在我们把图片添加到.slides中,并且还需要将.dot添加到.container-dots。总的图片数量和总的导航点的数量应该相同,例如有五个图像,那么应该有五个导航点。

// 将图片和导航点动态添加到容器中
images.map((img) => {
    // Creating Image Element and adding src of that image
    var imgTag = document.createElement("img");
    imgTag.src = img.src;

    // Creating Dot (div) Element adding 'dot' class to it
    var dot = document.createElement("div");
    dot.classList.add("dot");

    //    Appending the image and dots to respective container
    slides.appendChild(imgTag);
    containerDots.appendChild(dot);
});

现在轮到切换按钮了。我们需要的两个按钮.prev和.next已经添加到了HTML代码中,现在我们只需要让它们工作就可以了。

下一张图片按钮

// 下一张图片按钮点击事件
const nextSlide = () => {
        // it will update the slideIndex on the basis of the images.length as it gets greater than images.length, this will initialize to the 1
    if (slideIndex !== images.length) {
        ++slideIndex;
    } else if (slideIndex === images.length) {
        slideIndex = 1;
    }
};

const nextBtn = document.querySelector(".next");
nextBtn.onclick = nextSlide;

上一张图片按钮

// 上一张图片按钮点击事件
const prevSlide = () => {
        // It will check if the slideIndex is less equal to 1 then change it to the images.legnth, it will enable infinite scrolling
    if (slideIndex !== 1) {
        --slideIndex;
    } else if (slideIndex === 1) {
        slideIndex = images.length;
    }
};

const prevBtn = document.querySelector(".prev");
prevBtn.onclick = prevSlide;

现在依靠slideIndex变量,这些按钮将允许你无限滚动。

但是在实现它之后你会看到图像没有显示,这是因为我们还没有根据slideIndex更新图像。

// 根据 [data-active] 标签更新图片以及当前导航点
function updateImageAndDot() {
    /* ...........Updating Image.............. */
    const activeSlide = slides.querySelector("[data-active]");
    slides.children[slideIndex - 1].dataset.active = true;
    activeSlide && delete activeSlide.dataset.active;

    /* ...........Updating Dots.............. */
    const activeDot = containerDots.querySelector("[data-active]");
    containerDots.children[slideIndex - 1].dataset.active = true;
    activeDot && delete activeDot.dataset.active;
}

这里我们得到了activeSlide和activeDot。有一个[data-active]属性,然后基于slideIndex我们将.slides和.container-dots子级设置为激活状态 (data-active="true"),且如果有我们之前查询过的activeSlide,那么删除它(这是以前活动的图片和导航点)。在此之后,我们将只有一张当前处于活动状态的图片和导航点。

最后我们需要在nextSlide和prevSlide函数内调用这个函数。

const nextSlide = () => {
    /* .... */
    updateImageAndDot();
};

const prevSlide = () => {
    /* .... */
    updateImageAndDot();
};

我们还需要在全局范围内调用updateImageAndDot。这将允许它在页面加载时显示图像和导航点。

// Show the Image as the page loads;
updateImageAndDot();

好的,现在我们要实现另一个功能——当用户按下导航点时,将用户带到相应的图片。

这不难,我们只需要创建名为moveDot的函数,然后将事件监听器添加到每个导航点。

// It helps to move the dot, it take "index" as parameter and update the slideIndex
function moveDot(index) {
    slideIndex = index;
    updateImageAndDot();    // to update the image and dot
}

// Adding EventListener to All dots so that when user click on it trigger move dots;
const dots = containerDots.querySelectorAll("*").forEach((dot, index) => {
    dot.addEventListener("click", () => {
        moveDot(index + 1);
    });
});

完成,现在让我们看看完整的JavaScript代码:

const slides = document.querySelector(".slides");
const containerDots = document.querySelector(".container-dots");

var slideIndex = 1;

// Images container
const images = [
    { src: "https://rb.gy/ohx0bd" },
    { src: "https://rb.gy/gggxy8" },
    { src: "https://rb.gy/z2a0fy" },
    { src: "https://rb.gy/nsefjh" },
    { src: "https://rb.gy/dssu2a" }
];

// Adding images and dots to the Respective Container
images.map((img) => {
    // Creating Image Element and adding src of that image
    var imgTag = document.createElement("img");
    imgTag.src = img.src;

    // Creating Dot (div) Element adding 'dot' class to it
    var dot = document.createElement("div");
    dot.classList.add("dot");

    //    Appending the image and dots to respective container
    slides.appendChild(imgTag);
    containerDots.appendChild(dot);
});

// Adding EventListener to All dots so that when user click on it trigger move dots;
const dots = containerDots.querySelectorAll("*").forEach((dot, index) => {
    dot.addEventListener("click", () => {
        moveDot(index + 1);
    });
});

// It helps to move the dot, it take "index" as parameter and update the slideIndex
function moveDot(index) {
    slideIndex = index;
    updateImageAndDot();
}

// Update Image And Slide Dot according to the [data-active]
function updateImageAndDot() {
    /* ...........Updating Image.............. */
    const activeSlide = slides.querySelector("[data-active]");
    slides.children[slideIndex - 1].dataset.active = true;
    activeSlide && delete activeSlide.dataset.active;

    /* ...........Updating Dots.............. */
    const activeDot = containerDots.querySelector("[data-active]");
    containerDots.children[slideIndex - 1].dataset.active = true;
    activeDot && delete activeDot.dataset.active;
}

// Slide Next Button Click Event
const nextSlide = () => {
    // it will update the slideIndex on the basis of the images.length as it gets greater than images.length, this will initialize to the 1
    if (slideIndex !== images.length) {
        ++slideIndex;
    } else if (slideIndex === images.length) {
        slideIndex = 1;
    }
    updateImageAndDot();
};

const nextBtn = document.querySelector(".next");
nextBtn.onclick = nextSlide;

// Slide Previous Button Click Event
const prevSlide = () => {
    // It will check if the slideIndex is less equal to 1 then change it to the images.legnth, it will enable infinite scrolling
    if (slideIndex !== 1) {
        --slideIndex;
    } else if (slideIndex === 1) {
        slideIndex = images.length;
    }
    updateImageAndDot();
};

const prevBtn = document.querySelector(".prev");
prevBtn.onclick = prevSlide;

// Show the Image as the Page Loads;
updateImageAndDot();
文章目录