JavaScript:原生js实现轮播图

完全自己手写,能力有限,如果有bug请指出

这个做一个简易的轮播图,大概长这个样子,里面的图片就用色块来替代吧

 html布局为:

    <div class="big">

        <a href="javascript:;" class="left">&lt</a>
        <a href="javascript:;" class="right">&gt</a>
        <ul class="pic">
            <li style="background-color:pink;">1</li>
            <li style="background-color:aqua;">2</li>
            <li style="background-color:green;">3</li>
            <li style="background-color: yellow;">4</li>
            <li style="background-color:black;">5</li>
        </ul>

        <ul class="circle">

        </ul>
    </div>

主要的元素包括:

一个装下所有东西的大盒子big

左右边 的按钮  left  right

轮播图里面的图片 用ul li来装载  pic

下面的小圆圈  cicle 这个地方先不装li  原因下面再说

CSS布局为:

这个地方就不赘述了,没什么难的

    <style>
        * {
            padding: 0;
            margin: 0;
        }

        .big {
            position: relative;
            width: 500px;

            height: 350px;
            margin: 100px auto;
            /* background-color: red; */
            overflow: hidden;
        }

        .left {

            position: absolute;
            top: 175px;
            left: 0;
            z-index: 2;
            display: none;

        }

        .right {
            display: none;
            position: absolute;
            top: 175px;
            right: 0;

            z-index: 2;
        }

        .circle {
            position: absolute;
            bottom: 30px;
            left: 50%;
            height: 20px;

            transform: translate(-50%, 0);
            z-index: 2;


        }

        .circle li {
            list-style: none;
            float: left;
            margin-right: 10px;

            width: 20px;
            height: 20px;
            border-radius: 10px;
            background-color: gray;
        }

        .pic {
            position: absolute;
            top: 0;
            left: 0;
            height: 350px;

            z-index: 1;
        }

        .pic li {
            float: left;
            list-style: none;
            height: 350px;
            width: 500px;
        }
    </style>

JS实现

我们要实现的功能为:

1.鼠标放上去按钮浮现  鼠标移开按钮隐藏

2.下面的小圆圈个数与轮播图图片个数动态对应,不需要手动设置

3.点击按钮,轮播图向左或向右跳转,且下面的小圆圈的颜色与轮播图的图片对应(例如播放到第二张图  第二个小圆圈为红色)

4.点击下面的小圆圈也能实现跳转

5.鼠标不放上去自动播放  放上去就停止播放

引入元素

        var right = document.querySelector('.right');
        var left = document.querySelector('.left')
        var pic = document.querySelector('.pic')
        var cicle = document.querySelector('.circle')
        var big = document.querySelector('.big')

        var step = pic.children[0].offsetWidth;
        var num = pic.children.length

 这个地方

step对应的是轮播图中每个图片的大小,也就是一次运动的移动距离

num是轮播图中有多少个图片

1.鼠标放上去按钮浮现  鼠标移开按钮隐藏

这个很简单,给最大盒子big添加事件,当鼠标进入big时,显示left right按钮 ,当鼠标离开时隐藏

        big.addEventListener('mouseenter', function () {
            left.style.display = 'block'
            right.style.display = 'block'

        })

        big.addEventListener('mouseleave', function () {
            left.style.display = 'none'
            right.style.display = 'none'

        })

2.下面的小圆圈个数与轮播图图片个数动态对应

主要是一个for循环,循环次数等于轮播图图片数量,每次循环创造一个li,添加到circle的子元素中

        for (var i = 0; i < num; i++) {
            var lii = document.createElement('li')
            circle.appendChild(lii)

        }
        circle.style.width = 30 * num + 'px'
        pic.style.width = step * (num + 1) + 'px'
        circle.children[0].style.backgroundColor = 'red'

下面三句话的意思是:

由于是动态的 css中没有指定pic和circle的大小,这里动态赋予

一开始肯定处于第一张图片,故第一个小圆圈为红色

3.点击按钮,轮播图向左或向右跳转,且下面的小圆圈的颜色与轮播图的图片对应

首先介绍一个函数,这个函数的作用是,将obj对象移动到target位置,在移动前执行first函数,移动后执行callback函数,这两个函数可以为空。

        function fn(obj, target, first, callback) {

            if (obj.timer) {
                clearInterval(obj.timer)
            }

            if (first) {
                first()
            }


            obj.timer = setInterval(function () {
                //移动先快后慢
                var distance = (target - obj.offsetLeft) / 10;
                //考虑到了distance为负数的情况
                distance = distance > 0 ? Math.ceil(distance) : Math.floor(distance)

                obj.style.left = obj.offsetLeft + distance + 'px'
                if (obj.offsetLeft == target) {
                    clearInterval(obj.timer)
                    if (callback) {
                        callback()
                    }

                }
            }, 20)
        }

值得注意的是,这里distance的赋值是递减的,也就是说移动会是先快后慢

这个地方我们还想实现一个功能:

当我到达最后一张图的时候,我再点击right按钮,我希望其还是往后面滚动,但是实际上已经到了第一张图片,即无缝滚动

思路是,我一开始给pic的最后再加一张图片,这个图片与第一张图片一模一样,在这个例子中,pic有五个图片,但是实际上有六个,因为我在最后再加了一个与第一张完全一样的图片:

接下来的讲解中我将用数字代表这些图片

        var last = pic.children[0].cloneNode(true)
        pic.appendChild(last);

为了完成轮播图的功能,我再设定一个变量flag,含义为当前的轮播图播放到哪一张图了

var flag = 0

 以right按钮为例,给其添加点击事件:

        right.addEventListener('click', function () {
            if (flag == num) {
                flag = 0;
                pic.style.left = 0
            }

            if (flag < num - 1) {
                flag = parseInt(flag) + parseInt(1)

                fn(pic, -step * flag, function () {
                    circle.children[flag].style.backgroundColor = 'red';
                    circle.children[flag - 1].style.backgroundColor = 'gray'
                })

            }
            else if (flag == num - 1) {

                flag = parseInt(flag) + parseInt(1)
                fn(pic, -step * flag, function () {
                    circle.children[0].style.backgroundColor = 'red';
                    circle.children[num - 1].style.backgroundColor = 'gray'

                }, function () {

                })


            }

        })

这里有一些判断语句:

第一个if表示,当我已经到达最后一张(第二个1),让pic快速的,没有动画的移动到第一张的位置,这样就能实现无缝播放的功能

第二个if表示,当我到达除最后一张(5)的前几张时,先给flag+1,示意接下来要去下一张,然后让pic运动到下一张位置,最后让后面一张的小圆圈变红,前一张的小圆圈变灰

当我移动到5时,接下来移动应该到 第二个1 ,但是应该是第一个小圆圈变红,最后一个小圆圈边灰

left按钮类似

        left.addEventListener('click', function () {
            if (flag > 0) {
                flag -= 1
                fn(pic, -step * flag, function () {
                    circle.children[flag].style.backgroundColor = 'red'
                    circle.children[flag + 1].style.backgroundColor = 'gray'
                })

            }
            else if (flag == 0) {
                flag = num;
                pic.style.left = -step * (num) + 'px';
                flag--
                fn(pic, -step * flag, function () {
                    circle.children[num - 1].style.backgroundColor = 'red'
                    circle.children[0].style.backgroundColor = 'gray'
                })


            }
        })

这里少了一个判断语句,是因为其到达 第一个1时  不需要再往前走了,而是直接马上回到第二个1即可。

4.点击下面的小圆圈也能实现跳转

用for循环给每一个小圆圈赋予响应。

为了知道点的是哪个小圆圈,给每个li加了一个自定义变量index,每次点击时,可以根据index知道需要运动多少,给flag赋值多少

        for (var i = 0; i < circle.children.length; i++) {
            circle.children[i].setAttribute('index', i);
            circle.children[i].addEventListener('click', function () {
                var index = this.getAttribute('index');
                fn(pic, -step * index)
                for (var i = 0; i < circle.children.length; i++) {
                    circle.children[i].style.backgroundColor = 'gray';
                }
                this.style.backgroundColor = 'red'
                flag = index;
            })
        }

5.鼠标不放上去自动播放  放上去就停止播放

这个地方很简单,自动播放就效果而已其实就是,每隔一段时间点击了right一次,那我们可以认为模拟这一动作

由于进入页面就要开始播放,故需要定义:

        var animi = setInterval(function () {
            right.click()
        }, 2000)

也就是2s执行一次right.click(),相当于模拟了一次点击right

再在big事件中添加事件:

        big.addEventListener('mouseenter', function () {
            left.style.display = 'block'
            right.style.display = 'block'
            clearInterval(animi)
            animi = null

        })

        big.addEventListener('mouseleave', function () {
            left.style.display = 'none'
            right.style.display = 'none'
            animi = setInterval(function () {
                right.click()
            }, 2000)

        })

完全实现功能

完整代码:

<!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>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        .big {
            position: relative;
            width: 500px;

            height: 350px;
            margin: 100px auto;
            /* background-color: red; */
            overflow: hidden;
        }

        .left {

            position: absolute;
            top: 175px;
            left: 0;
            z-index: 2;
            display: none;

        }

        .right {
            display: none;
            position: absolute;
            top: 175px;
            right: 0;

            z-index: 2;
        }

        .circle {
            position: absolute;
            bottom: 30px;
            left: 50%;
            height: 20px;

            transform: translate(-50%, 0);
            z-index: 2;


        }

        .circle li {
            list-style: none;
            float: left;
            margin-right: 10px;

            width: 20px;
            height: 20px;
            border-radius: 10px;
            background-color: gray;
        }

        .pic {
            position: absolute;
            top: 0;
            left: 0;
            height: 350px;

            z-index: 1;
        }

        .pic li {
            float: left;
            list-style: none;
            height: 350px;
            width: 500px;
        }
    </style>
</head>

<body>
    <div class="big">

        <a href="javascript:;" class="left">&lt</a>
        <a href="javascript:;" class="right">&gt</a>
        <ul class="pic">
            <li style="background-color:pink;">1</li>
            <li style="background-color:aqua;">2</li>
            <li style="background-color:green;">3</li>
            <li style="background-color: yellow;">4</li>
            <li style="background-color:black;">5</li>
        </ul>

        <ul class="circle">

        </ul>
    </div>


    <script>

        var right = document.querySelector('.right');
        var left = document.querySelector('.left')
        var pic = document.querySelector('.pic')
        var circle = document.querySelector('.circle')
        var big = document.querySelector('.big')

        var step = pic.children[0].offsetWidth;
        var num = pic.children.length




        for (var i = 0; i < num; i++) {
            var lii = document.createElement('li')
            circle.appendChild(lii)

        }
        circle.style.width = 30 * num + 'px'
        pic.style.width = step * (num + 1) + 'px'
        circle.children[0].style.backgroundColor = 'red'

        var last = pic.children[0].cloneNode(true)
        pic.appendChild(last);
        console.log(pic);

        var flag = 0

        var animi = setInterval(function () {
            right.click()
        }, 2000)



        for (var i = 0; i < circle.children.length; i++) {
            circle.children[i].setAttribute('index', i);
            circle.children[i].addEventListener('click', function () {
                var index = this.getAttribute('index');
                fn(pic, -step * index)
                for (var i = 0; i < circle.children.length; i++) {
                    circle.children[i].style.backgroundColor = 'gray';
                }
                this.style.backgroundColor = 'red'
                flag = index;
            })
        }




        big.addEventListener('mouseenter', function () {
            left.style.display = 'block'
            right.style.display = 'block'
            clearInterval(animi)
            animi = null

        })

        big.addEventListener('mouseleave', function () {
            left.style.display = 'none'
            right.style.display = 'none'
            animi = setInterval(function () {
                right.click()
            }, 2000)

        })

        right.addEventListener('click', function () {
            if (flag == num) {
                flag = 0;
                pic.style.left = 0
            }

            if (flag < num - 1) {
                flag = parseInt(flag) + parseInt(1)

                fn(pic, -step * flag, function () {
                    circle.children[flag].style.backgroundColor = 'red';
                    circle.children[flag - 1].style.backgroundColor = 'gray'
                })

            }
            else if (flag == num - 1) {

                flag = parseInt(flag) + parseInt(1)
                fn(pic, -step * flag, function () {
                    circle.children[0].style.backgroundColor = 'red';
                    circle.children[num - 1].style.backgroundColor = 'gray'

                }, function () {

                })


            }

        })

        left.addEventListener('click', function () {
            if (flag > 0) {
                flag -= 1
                fn(pic, -step * flag, function () {
                    circle.children[flag].style.backgroundColor = 'red'
                    circle.children[flag + 1].style.backgroundColor = 'gray'
                })

            }
            else if (flag == 0) {
                flag = num;
                pic.style.left = -step * (num) + 'px';
                flag--
                fn(pic, -step * flag, function () {
                    circle.children[num - 1].style.backgroundColor = 'red'
                    circle.children[0].style.backgroundColor = 'gray'
                })



            }
        })


        function fn(obj, target, first, callback) {

            if (obj.timer) {
                clearInterval(obj.timer)
            }

            if (first) {
                first()
            }


            obj.timer = setInterval(function () {

                var distance = (target - obj.offsetLeft) / 10;

                distance = distance > 0 ? Math.ceil(distance) : Math.floor(distance)

                obj.style.left = obj.offsetLeft + distance + 'px'
                if (obj.offsetLeft == target) {
                    clearInterval(obj.timer)
                    if (callback) {
                        callback()
                    }

                }
            }, 20)
        }





    </script>
</body>

</html>

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值