IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> js实现无缝轮播图 -> 正文阅读

[JavaScript知识库]js实现无缝轮播图

一、轮播图需求分析

  • 需要实现每隔一定时间进行下一张图片的自动轮播
  • 需要点击左右按钮可以进行上下图片的切换
  • 显示当前位置的小圆点
  • 点击小圆点可以切换到对应的图片上
  • 鼠标移入可视区时,停止轮播,显示左右按钮

下面我们来看一下效果图:?

二、轮播图的原理

  1. 图片移动实现原理:利用浮动将所有所有照片依次排成一行,给这一长串图片ul添加一个父级的遮罩(就是可视区),?每次只显示一张图,其余的都隐藏起来。对图片添加绝对定位,通过控制left属性,实现照片的移?动。
  2. 图片移动动画原理:从当前图片移动到下一张图片位置,计划出每次移动的固定步长,通过添加定时器的方法,每次? 向左移动相同的步长,实现动画效果。
  3. 图片定位停止原理:每一张照片都有相同的宽度,通过检测定每次移动后,判断这一长串图片ul 左偏移的宽度是否已经超过或者是等于 一个图片的宽度了,如果超出或者刚好等于,说明已经移动到位,可以将定时器清除并设置left属性为0(确保每次移动完成后图片左边与可视区的左边框刚好贴近),来停止动画。
  4. 无缝衔接原理:由于图片的基本移动原理。要想实现无缝衔接,两张图片就必须紧贴在一起。(我这里写的轮播图默认是向左移动的)所以当每一次向左轮播移动图片完成后,需要把前面那一张图片通过appendChild()方法(这个方法除了在原来的父元素上添加子元素之外还有一个功能就是,将原来的子元素删除,重新插入到父元素中子元素的最后一个。)把它移动到整个长串图片最后面,这样每一次在可视区显示的图片就相当于整个长串图片的第一张;如果是向右移动(就是移动到当前可视区显示图片的上一张图片==最后哪一张图片),先把整个长串图片ul?左偏移一个图片的宽度,再通过insertBefore()方法,把最后面哪一张图片插入到可视区显示的图片的前面去。然后再根据移动原理就可以实现图片的无缝连接拉。
  5. 左右点击切换原理(点击左按钮整个长串图片向右移,点击右按钮整个长串图片向左移):点击左按钮,先把图片插到可视区显示的图片的前面并设置left? 后移动;右按钮,先移动,移动完成后把图片插回到最后面去。?这里需要注意与自动轮播之间的冲突。当点击事件触发之后,停止自动轮播计时器,开始切换。当动画结束后再次添加自动轮播计时器。

  6. 小圆点的位置显示原理:每次触发动画时,通过全局变量标记,获取当前图片下标索引,操作清除所有小圆点,然后指定一页添加样式。点击小圆点,先判断所点击的小圆点对应图片的下标索引是在 当前可视区显示的图片下标索引的左边还是右边,然后计算两点之间的差值,通过差值和时间间隔,计算出每次移动的步长,按照移动动画的原理,移动到所点击小圆点对应的图片的位置,在可视区显示出来。?

图片演示:

? ?这是默认自动轮播图片时(或者是点击一次右按钮时)? 图片切换的一个过程:

? ?点击左按钮时图片切换的一个过程:

?

三、完整代码实现

<!DOCTYPE html>
<html>

<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        
        ul {
            list-style: none;
        }
        
        img {
            width: 500px;
            height: 300px;
            vertical-align: top;
        }
        /*取消图片底部3像素距离*/
        
        .box {
            width: 500px;
            height: 300px;
            margin: 150px auto;
            background-color: pink;
            border: 2px solid tan;
            position: relative;
            overflow: hidden;
        }
        
        .box #ul li {
            float: left;
        }
        
        .box #ul {
            position: absolute;
            left: 0;
            top: 0;
        }
        
        #left,
        #right {
            position: absolute;
            width: 48px;
            height: 48px;
            border-radius: 50%;
            cursor: pointer;
            display: none;
        }
        
        #left {
            background: url('./img/left-btn.png') no-repeat;
            background-size: 100%;
            left: 10px;
            top: 50%;
            transform: translate(0, -50%);
        }
        
        #right {
            background: url('./img/right-btn.png') no-repeat;
            background-size: 100%;
            right: 10px;
            top: 50%;
            transform: translate(0, -50%);
        }
        
        .dot {
            /* height: 50px; */
            position: absolute;
            bottom: 10px;
            left: 50%;
            transform: translate(-50%);
        }
        
        #dotul {
            text-align: center;
        }
        
        #dotul li {
            margin: 0 8px;
            border-radius: 50%;
            border: 2px solid white;
            background-color: white;
            font-size: 12px;
            width: 15px;
            height: 15px;
            line-height: 15px;
            display: inline-block;
            cursor: pointer;
        }
        
        #dotul .selected {
            background-color: tan;
        }
    </style>
</head>

<body>
    <div class="box" id="screen">
        <ul id="ul">
            <li><img src="./img/1.jpg" alt="" /></li>
            <li><img src="./img/2.jpg" alt="" /></li>
            <li><img src="./img/3.jpg" alt="" /></li>
            <li><img src="./img/4.jpg" alt="" /></li>
            <li><img src="./img/5.jpg" alt="" /></li>
        </ul>
        <div id="left"></div>
        <div id="right"></div>
        <div class="dot">
            <ul id="dotul">
                <!-- <li>1</li>
                <li>2</li>
                <li>3</li>
                <li>4</li>
                <li>5</li> -->
            </ul>
        </div>
    </div>
    <script>
        var box = document.querySelector('#screen');
        //获取left right按钮
        var left = document.querySelector('#left')
        var right = document.querySelector('#right')

        //设置ul的宽度 
        var ul = document.querySelector("#ul")
        ul.style.width = ul.children[0].offsetWidth * ul.children.length + 'px';
        // console.log(ul.style.width);

        //每个li 的 数组
        var lis = ul.children;
        // console.log(lis);
        // console.log(ul.childNodes);

        //ul 圆点序列
        var dot_ul = document.getElementById('dotul');

        var timer;

        var cur_left;
        //节流阀
        var flag = true;
        //用来记录当前显示的是第几张图 刚开始设置默认为0第一张  按从0开始
        var cur_img_index = 0;

        box.addEventListener('mouseenter', function() {
            clearInterval(in_timer)
            show_btn()

        });
        box.addEventListener('mouseleave', function() {
            clearInterval(in_timer)
            in_timer = setInterval(swiper, 2500);
            hide_btn()

        })


        // 左右两边按钮 的 显示 隐藏
        function hide_btn() {

            left.style.display = 'none';
            right.style.display = 'none';
        }

        function show_btn() {
            left.style.display = 'block';
            right.style.display = 'block';
        }

        // for (let h = 0; h < lis.length; h++) {
        //     //鼠标进入轮播区域时  显示两边按钮
        //     lis[h].addEventListener('mouseenter', show_btn);

        //     //鼠标离开轮播区域时  隐藏两边按钮
        //     lis[h].addEventListener('mouseleave', hide_btn);
        // }

        //当鼠标移入左或右按钮时 给它设置的样式
        function left_right_btn() {
            this.style.display = 'block';
            this.style.opacity = 0.7
        }
        left.addEventListener('mouseenter', left_right_btn);
        right.addEventListener('mouseenter', left_right_btn);
        left.addEventListener('mouseleave', function() {
            this.style.opacity = 1;
        });
        right.addEventListener('mouseleave', function() {
            this.style.opacity = 1;
        });


        //给 被选中的小圆点 设置 类名 
        function set_className(index) {
            for (let o = 0; o < lis.length; o++) {
                dot_ul.children[o].className = '';
            }
            dot_ul.children[index].className = 'selected';
        }

        //无缝轮播图 
        function swiper() {
            if (flag) {
                cur_left = 0;
                timer = setInterval(function() {
                    cur_left -= 50;
                    ul.style.left = cur_left + "px";
                    // console.log(ul.offsetLeft);
                    if (ul.offsetLeft <= '-' + ul.children[0].offsetWidth) {
                        cur_img_index += 1;
                        if (cur_img_index > 4) {
                            cur_img_index = 0;

                        }
                        set_className(cur_img_index);

                        console.log('当前显示的图片下标索引(从0开始):' + cur_img_index);

                        clearInterval(timer);
                        ul.appendChild(ul.children[0]);
                        ul.style.left = 0 + 'px';
                        flag = true;
                    }
                }, 50);
                flag = false; //***节流阀 为了防止 在未完成上一张图片轮播 就接着要轮播下一张图片 
            }

        };

        //点击左边按钮时 执行的操作
        function left_swiper() {
            if (flag) {
                clearInterval(in_timer); //先把 实现自动轮播的定时器 清除掉 防止发生冲突
                ul.style.left = "-" + ul.children[0].offsetWidth + "px"; //先把整个ul 左偏移一个li的宽度 -500px
                cur_left = ul.offsetLeft;
                ul.insertBefore(ul.lastElementChild, ul.children[0]); //然后通过insertBefore方法,把最后一个li节点,插入到当前显示图片(也就是第一个)的li节点前面
                //然后在通过定时器的方式,对ul的left属性值按一定的值(这里我设置的是50)进行累加直到left值大于等于0时,在清除这个定时器,再从新设置ul的left属性值为0(因为累加后可能会有多出来的)
                //当实现左按钮的操作后 在调用in_timer = setInterval(swiper, 2500);继续来实现自动的循环轮播
                timer = setInterval(function() {
                    cur_left += 50;
                    ul.style.left = cur_left + 'px'
                    if (ul.offsetLeft >= 0) {
                        cur_img_index -= 1;
                        if (cur_img_index < 0) {
                            cur_img_index = 4;
                        }
                        set_className(cur_img_index);

                        console.log('当前显示的图片下标索引(从0开始):' + cur_img_index);

                        clearInterval(timer);
                        ul.style.left = 0 + 'px';
                        flag = true;
                        in_timer = setInterval(swiper, 2500);
                    }

                }, 50)
                flag = false;
            }

        }
        left.addEventListener('click', left_swiper);

        function right_swiper() {
            if (flag) {
                clearInterval(in_timer); //先清除
                cur_left = 0;

                timer = setInterval(function() {
                    cur_left -= 50;
                    ul.style.left = cur_left + "px";
                    // console.log(ul.offsetLeft);
                    if (ul.offsetLeft <= '-' + ul.children[0].offsetWidth) {
                        cur_img_index += 1;
                        if (cur_img_index > 4) {
                            cur_img_index = 0;
                        }
                        set_className(cur_img_index);

                        console.log('当前显示的图片下标索引(从0开始):' + cur_img_index);

                        clearInterval(timer);
                        ul.appendChild(ul.children[0]);
                        ul.style.left = 0 + 'px';
                        flag = true;
                        in_timer = setInterval(swiper, 2500);
                    }
                }, 50);
                flag = false;

            }
        };
        right.addEventListener('click', right_swiper);



        //1 创建 对应 图片 的小圆点 并给它们设置点击事件
        //2(点击小圆点后,轮播图 展示 点击的小圆点对应的图片 )
        for (let i = 0; i < lis.length; i++) {
            var dot_li = document.createElement('li');
            dot_li.innerHTML = i + 1;

            dot_ul.appendChild(dot_li);
            dot_li.addEventListener('click', function() {
                if (flag) {
                    // 当前显示图片下标 大于 点击的小图点的下标 时
                    if (cur_img_index > i) {
                        clearInterval(in_timer);
                        //当前显示的图片 到 点击的图片的距离  
                        var cur_to_target = cur_img_index - i;
                        ul.style.left = '-' + ul.children[0].offsetWidth * cur_to_target + 'px';
                        cur_left = ul.offsetLeft;

                        for (let j = 0; j < cur_to_target; j++) {
                            //从后边 依次把图片放回 当前显示的图片的前边
                            ul.insertBefore(ul.lastElementChild, ul.children[0])
                        }

                        timer = setInterval(function() {
                            cur_left += 50 * cur_to_target;
                            ul.style.left = cur_left + 'px'
                            if (ul.offsetLeft >= 0) {
                                clearInterval(timer);

                                cur_img_index = i;
                                set_className(cur_img_index);
                                console.log('当前显示的图片下标索引(从0开始):' + cur_img_index);

                                ul.style.left = 0 + 'px';
                                flag = true;
                                in_timer = setInterval(swiper, 2500);
                            }

                        }, 50)

                        flag = false;
                    } else if (i > cur_img_index) { // 当前显示图片下标 小于 点击的小图点的下标 时

                        clearInterval(in_timer);
                        //当前显示的图片 到 点击的图片的距离  
                        var cur_to_target = i - cur_img_index;
                        cur_left = 0;

                        timer = setInterval(function() {
                            cur_left -= (50 * cur_to_target);
                            ul.style.left = cur_left + 'px'
                                // console.log(ul.offsetLeft);
                            if (ul.offsetLeft <= '-' + (ul.children[0].offsetWidth * cur_to_target)) {
                                for (let k = 0; k < cur_to_target; k++) {
                                    //**
                                    ul.appendChild(ul.children[0]);
                                }
                                clearInterval(timer);
                                cur_img_index = i;
                                set_className(cur_img_index);
                                console.log('当前显示的图片下标索引(从0开始):' + cur_img_index);

                                ul.style.left = 0 + 'px';
                                flag = true;
                                in_timer = setInterval(swiper, 2500);


                            }

                        }, 50)
                        flag = false;
                    }
                }
            })

        }


        //刚开始 给第一个小圆点 设置 类名 ----加上背景颜色
        //这一段代码必须放到 创建小圆点 后  要不然会提示错误Uncaught TypeError: Cannot set property 'className' of undefined
        //因为 你要是放上面 就相当于 小圆点没创建好 你就给它 设置类名 它肯定会报错的 所以放到上面循环创建对应小圆点后  就可以了
        dot_ul.children[cur_img_index].className = 'selected';

        // 利用定时器  来实现 无缝循环轮播
        console.log('当前显示的图片下标索引(从0开始):' + cur_img_index);
        var in_timer = setInterval(swiper, 2500);
    </script>

</body>

</html>

git:https://gitee.com/otnr-006/js-seamless-rotation-charthttps://gitee.com/otnr-006/js-seamless-rotation-charthttps://gitee.com/otnr-006/js-seamless-rotation-chart

如果还可以优化的更好或者是存在什么问题,欢迎各位大佬补充啊!!!

ppp

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-12 13:04:57  更:2021-09-12 13:05:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 16:41:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码