原生JS 实现轮播图效果

本文详细介绍了如何使用原生JavaScript实现一个轮播图功能,包括HTML和CSS的简洁布局,以及JS中图片的平移效果和过渡动画。通过创建Slider类,实现了图片的切换、底部圆圈的点击事件以及左右按钮的切换功能,同时讨论了特殊情况下(如首尾图片切换)的处理策略。
摘要由CSDN通过智能技术生成

原生JS

原生态JS是指遵循ECMAScript标准的javascript,在不使用框架的情况下考察我们对于对JS语法的了解和API的掌握。虽然目前大都是根据框架来进行前端的编程,但对于原生JS的掌握还是很重要的吧,本代码实现的效果如下:

原文已经失效
请添加图片描述

根据传入的图片数量在页面的底部呈现轮播图的图片数量和当前为第几张图片,点击相应的圆圈则可以跳转至其他图片;左右两个按钮同样可以实现图片的切换,如果当前为第一张或者最后一张图片,点击左移或者右移按钮即可完成循环操作,从第一张图片跳转至最后一张图片,且切换图片的效果还在。具体的实现如下:

思路阐述

HTML部分

既然说是原生JS实现,那么html和CSS我们能少用就少用。整个html内,仅写入一个div,其CSS格式表示其铺满整个屏幕,引入额外写的index.js后,在body下新建一个Slider对象,并插入我们要轮播的图片。整体代码仅此而已,其详细代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>last experiment</title>
    <script src="index.js"></script>
</head>
<body>
    <div style="
                position: fixed;
                top:0px;
                bottom: 0px;
                left: 0px;
                right: 0px;
                background-color: #333;">
    </div>
</body>
<script>
    new Slider(
        document.querySelector('div'),
        [
            'images/1.png',
            'images/3.jpg',
            'images/25.png'
        ]
    )
</script>
</html>

JS部分

我的思路是将所有图片加载在一个div中,我们称该div之为innerct,该div采取fixed布局,让图片在一整行内显示,每个图片与该div的大小一致。根据该div平移的距离即可实现页面呈现的图片的切换,同时带平移效果。

思路实现的目标就是下图第一行的内容,红框表示当前展示的图片,如现在页面展示的就是编号为 Ⅱ 的图片。但是假如当前图片为第一张,同时我又按下了左移按钮,根据轮播图的特性,我应该跳转至图片三,同时页面呈现出图片向右滑动,即左移的效果,呈现出编号为 Ⅲ 的图片。

为了实现这个效果,那么innerct内的图片排列应该是下图第二行的这种情况。同时,当页面呈现的图片为第二行的第一个 编号为 Ⅲ 时,将此时的第二行的第一个 Ⅲ 瞬移至 第二行的第四个图片 Ⅲ 。同理,当页面呈现第二行的第五个图片 Ⅰ 时,再将图片瞬移至第二行的第二个 Ⅰ 图片即可不露声色的完成轮播图的效果实现。那么此时我们需要解决的就是如何实现“瞬移“操作。

图片的平移效果我们采取了CSS样式中的过渡效果,那我们将平移的过程设置在在1s内完成,就可以展示出平移的过程,而页面不会呈现出图片的瞬间切换。根据这个平移的实现思路,我们就可以设置当页面呈现的图片为第二行的第一个Ⅲ 和 第五个 Ⅰ时,将平移的过程设置在0s完成,将图片瞬移至第二行的第四个 Ⅲ 和 第二行的第二个 Ⅰ。其他位置时,平移过程的过渡效果再次恢复为1s内完成即可。

请添加图片描述

代码实现

根据以上的思路,我们就可以进行JS的编程了。代码分为两部分一个是Slider类,来实现轮播图对象;一个是工具函数来实现异步睡眠操作。由于前端的知识点比较杂糅,具体的讲解,我在代码中进行注释来一一说明,下面我们开始 >灬<。

class Slider {
    constructor(ct, imgs) { //该类传入的参数为一个dom元素和要轮播图片的list

        this.currentPage = 0; //当前页面展示的图片下标
        this.pageCount = imgs.length; //轮播图的数量 aka,图片list的 大小
        // let width = window.innerWidth;//全屏
        let width = ct.offsetWidth; //此处实现的是让图片全屏显示,使用上面的语句也可以实现,但由于本次html中只有一个div,用该div的外轮廓宽也是可以的。
        this.width = width;
        let height = ct.offsetHeight;

        this.innerCt = document.createElement('div');
        this.innerCt.style.cssText = `width: ${width * (imgs.length + 2)}px;//设置图片所在div的宽度,其宽度为 图片的数据 + 首部的最后一张图片 和 尾部的第一张图片,aka,图片list的长度 + 2。
        height:100%;padding:0;margin:0;transition:transform 1s ease;left:0`;//设置transition 过渡效果,平移 持续时间为1s 过渡方式为ease
        // 'width:' + width * imgs.length + 'px;' + 'height:100%;padding:0;' + 'margin:0;' + 'transition:transform 1s ease';//ease先快后慢;放图像个数的窗口
        ct.appendChild(this.innerCt);//将innerct放入到dom元素中去

        let circleCt = document.createElement('div');//此处为页面底部的圆圈
        circleCt.style.cssText = `position:fixed;opacity:0.6;bottom:0px;width:100%;padding:10px 0`;//让圆圈布局在底部
        circleCt.setAttribute('align', 'center');//效果 剧中
        ct.appendChild(circleCt);
        this.circles = [];

        let ct3 = document.createElement('div');//新建一个div,将最后一个图片放入其中,再将该div放入innerct中
        ct3.style.cssText = `width:${width}px;height:${height};float:left`;
        ct3.setAttribute('align', 'center');//左右居中
        let img3 = new Image();
        img3.src = imgs[this.pageCount - 1];
        img3.style.cssText = `max-width:${width}px;max-height:${height}px`;
        img3.onload = () => {
            img3.style.marginTop = (height - img3.height) / 2 + 'px';//垂直居中
        }
        ct3.appendChild(img3);
        this.innerCt.appendChild(ct3);

        imgs.forEach((item, index) => {//将图片按照 list的顺序放入其中,并在其中添加圆圈的点击事件
            let ct1 = document.createElement('div');
            ct1.style.cssText = `width:${width}px;height:${height};float:left`;
            // 'width:' + width + 'px;' + 'height:' + height + 'px;' + 'float:left;';
            ct1.setAttribute('align', 'center');//左右居中
            let img = new Image();
            img.src = item;
            img.style.cssText = `max-width:${width}px;max-height:${height}px`;
            // 'max-width:' + width + 'px;' + 'max-height:' + height + 'px;';
            img.onload = () => {
                img.style.marginTop = (height - img.height) / 2 + 'px';//垂直居中
            }
            ct1.appendChild(img);
            this.innerCt.appendChild(ct1);
            let c = document.createElement('div');
            c.style.cssText = `width:20px;height:20px;
            border-radius:10px;background-coclor:white;
            display:inline-block;margin-right:10px;`;
            this.circles.push(c);
            circleCt.appendChild(c);
            c.addEventListener('click', () => {
                this.sliderTo(index);//点击小圆点有滑动的效果
            });
        });
        let ct2 = document.createElement('div');//新建一个div,将第一个图片放入其中,再将该div放入innerct中
        ct2.style.cssText = `width:${width}px;height:${height};float:left`;
        ct2.setAttribute('align', 'center');//左右居中
        let img2 = new Image();
        img2.src = imgs[0];
        img2.style.cssText = `max-width:${width}px;max-height:${height}px`;
        img2.onload = () => {
            img2.style.marginTop = (height - img2.height) / 2 + 'px';//垂直居中
        }
        ct2.appendChild(img2);
        this.innerCt.appendChild(ct2);

        let css = `position:absolute;//es6的新特性,反引号,可以查一下,使用极其方便,好像是加载速度不如''。
        top:50%;
        margin-top: -20px;
        height:40px;opacity:0.6;
        margin:0px auto;
        width:40px;
        padding:0 20px
        line-height:40px;
        background-color:#bbb;
        font-size:28px;
        cursor:pointer;`;
        let btnleft = document.createElement('div')
        btnleft.innerHTML = '<';
        btnleft.style.cssText = css;
        btnleft.style.left = '0px';

        let btnright = document.createElement('div')
        btnright.innerHTML = '>';
        btnright.style.cssText = css + `text-align: right;`;
        btnright.style.right = '0px';

        ct.appendChild(btnleft);
        ct.appendChild(btnright);//设置左右两个切换按钮,其下面所添加的点击事件就是之前思路中所强调的部分。

        btnleft.addEventListener('click', () => {
            if (this.currentPage === 0) {//当在第一个图片时点击了左移按钮。
                this.circles[this.currentPage].style.backgroundColor = 'white';当前的底部圆圈颜色变白。
                this.circles[this.pageCount - 1].style.backgroundColor = 'red';最后一个图片的底部圆圈的变为选中的颜色 红色
                let left = 0 * this.width;此时innerct平移的距离为 0 根据此前innerct里面插入div 的顺序,那么此时呈现的就是最后一个图片。
                this.innerCt.style.transform = 'translate(' + left + 'px,0px)';
                sleep(1000).then(() => {睡眠1秒完成,此处必须使用es6中的箭头函数,不如会引起this指向的改变
                    this.innerCt.style.transitionDuration = "0s";调用js中的 transition的api 将过渡时间设置为0
                    this.sliderTo(this.pageCount - 1);常规的移动图片至最后一张
                });
                sleep(1100).then(() => {同样等待上面的操作完成后,再将过渡时间设置为1s,此处只需要比上面完成的时间少一点即可
                    this.innerCt.style.transitionDuration = "1s";
                })
                return;
            }
            this.sliderTo(this.currentPage - 1);//当不涉及特色情况时,进行左移即可。
        });
        btnright.addEventListener('click', () => {//同理
            console.log('pagecount', this.currentPage);
            if (this.currentPage === this.pageCount - 1) {
                this.circles[this.currentPage].style.backgroundColor = 'white';
                this.circles[0].style.backgroundColor = 'red';
                let left = -(this.pageCount + 1) * this.width;
                this.innerCt.style.transform = 'translate(' + left + 'px,0px)';
                this.currentPage = 0;
                sleep(1000).then(() => {
                    this.innerCt.style.transitionDuration = "0s";
                    this.sliderTo(0);
                });
                sleep(1100).then(() => {
                    this.innerCt.style.transitionDuration = "1s";
                })
                return;
            }
            this.sliderTo(this.currentPage + 1);


        })
        for (let i = 0; i < this.circles.length; ++i) {
            this.circles[i].style.backgroundColor = 'white';
        }//底部的圆圈初始化

        this.circles[0].style.backgroundColor = 'white';
        this.circles[0].style.backgroundColor = 'red';
        let left = -1 * this.width;
        this.innerCt.style.transform = 'translate(' + left + 'px,0px)';
        this.currentPage = 0;//设置显示list中的第一个图片

    }
    sliderTo(num) {
        this.circles[this.currentPage].style.backgroundColor = 'white';
        this.circles[num].style.backgroundColor = 'red';//底部圆圈的切换
        let left = -(num + 1) * this.width;//innerct 平移距离的改变
        this.innerCt.style.transform = 'translate(' + left + 'px,0px)';
        this.currentPage = num;//当前照片的改变
        console.log('pagecurrent::::', this.currentPage);
    }
}

function sleep(time) {//es6增加的异步操作,此处需要异步来完成睡眠
    return new Promise((resolve) => setTimeout(resolve, time));
}

上面代码讲的十分详细了,我就不过多赘述了。

原文连接见上面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值