【Web APIs】移动端轮播图案例 ( 轮播图自动播放 | 设置无缝衔接滑动 | 手指滑动轮播图 | 完整代码示例 )

文章目录

代码下载地址 : https://download.csdn.net/download/han1202012/92520162

一、移动端轮播图案例


1、需求说明

实现如下功能 :

  • 自动轮播 : 不触摸时 , 轮播图自动轮播 ;
  • 左右滑动 : 滑动 超过 50 像素 则进行轮播图翻页 , 滑动低于 50 像素 则 回退到原来的位置 ; 滑动时无缝滚动 , 且 左右滑动两边无空白 ;
  • 滑动标识 : 右下角 小圆点 标识当前的轮播图索引 , 当前显示的轮播图索引显示长椭圆形 ;

2、HTML 结构布局

HTML 结构布局 :

轮播图有 3 张图片 , 实现左右都有内容效果 :

  • 右侧有内容 : 在 第 3 张 图片后面 , 放一张 图片 1 , 这样 处于 第 3 张图片 位置时 , 尝试向右滚动 , 可以看到 图片 1 ;
  • 左侧有内容 : 在 第 1 张 图片前面 , 放一张 图片 3 , 这样 处于 第 1 张图片 位置时 , 尝试向左滚动 , 可以看到 图片 3 ;

ul 标签 中 , 一共有 5 张图片 , 第 1 张图片 进作为 左滑 避免空白显示 的填充 , 并不参与轮播 , 只有 后 4 张图片 参与 轮播 , 只有 0 , 1 , 2 , 3 这四个索引 的 图片 参与 轮播图 播放 ;

无缝滚动效果 实现 :

  • 向右滑动时 : 如果滑动 目的索引值 大于等于 3 ( 从 索引 2 向右滑动到 索引 3 ) , 立刻跳转到 索引 0 , 也就是 ul 中的 第 2 张图片 , 显示图片内容 image/focus1.jpg ;
  • 向左滑动时 : 如果滑动 目的索引值 小于 0 ( 从 索引 0 向左滑动到 索引 -1 ) , 立刻跳转到 索引 2 , 也就是 ul 中的第 4 张图片 , 显示图片内容 image/focus3.jpg ;
html 复制代码
    <div class="focus">
        <ul>
            <li><img src="image/focus3.jpg" alt=""></li>
            <li><img src="image/focus1.jpg" alt=""></li>
            <li><img src="image/focus2.jpg" alt=""></li>
            <li><img src="image/focus3.jpg" alt=""></li>
            <li><img src="image/focus1.jpg" alt=""></li>
        </ul>
        <ol>
            <li class="current"></li>
            <li></li>
            <li></li>
        </ol>
    </div>

4、轮播图自动播放

轮播图 自动播放 :

  • 首先 , 定义轮播图索引号变量 index , 初始值为 0 , 用于 标记 当前显示 的轮播图位置 ;
  • 然后 , 开启一个 周期性定时器 , 每隔 2000 毫秒执行一次 滚动轮播逻辑 , 定时器 中 , 操作索引号 自增 1 , 切换到下一张轮播图 ;
  • 再后 , 在定时器 中 , 计算 ul 需要平移的水平距离 , 负的索引号 乘以 容器宽度 , 实现 ul 向左平移对应距离 ,
  • 最后 , 在定时器 中 , 通过 transform 的 translateX 属性 , 让 ul 水平平移计算好的距离 , 显示下一张轮播图 ;

代码示例 :

javascript 复制代码
            // 2. 利用定时器自动轮播图图片
            // 定义轮播图索引号变量 index , 初始值为 0 , 用于 标记 当前显示 的轮播图位置
            var index = 0;
            // 定义定时器变量 timer , 开启一个 周期性定时器 , 每隔 2000 毫秒执行一次 滚动轮播逻辑
            var timer = setInterval(function() {
                // 索引号 自增 1 , 切换到下一张轮播图
                index++;
                // 计算 ul 需要平移的水平距离 : 负的索引号 乘以 容器宽度 , 实现 ul 向左平移对应距离
                var translatex = -index * w;
                // 给 ul 设置 过渡动画 , 所有样式变化在 0.3 秒内 平滑完成 , 实现轮播图滑动的流畅效果
                ul.style.transition = 'all .3s';
                // 通过 transform 的 translateX 属性 , 让 ul 水平平移计算好的距离 , 显示下一张轮播图
                ul.style.transform = 'translateX(' + translatex + 'px)';
            }, 2000);

5、设置无缝衔接滑动

设置无缝衔接滑动 : 在 轮播图 最后一张图之后 , 再 追加一张 第一张图 的备份 , 实现无缝衔接 ;

等着我们 过渡完成 之后 , 再去判断 监听过渡完成的事件 transitionend ;

给 ul 添加 transitionend 事件监听 , 该事件在 CSS 过渡动画完成后触发 , 用于处理 无缝滚动逻辑

核心轮播图 有 3 张 :

  • 3 张核心图 的 右侧 , 再追加一张 第 1 张核心图 的 备份图 ; 在 处于 第 3 张核心图 位置时 , 向右滑动 , 可以看到 第 1 张核心图 的 备份图 , 避免出现空白 ;
  • 3 张核心图 的 左侧 , 再追加一张 第 3 张核心图 的 备份图 ; 在 处于 第 1 张核心图 位置时 , 向左滑动 , 可以看到 第 3 张核心图 的 备份图 , 避免出现空白

向右无缝滚动 : 判断索引号是否大于等于 3 ( 对应轮播图的 第 4 张 , 即 最后一张 有效图 之后的备用图 ) ;

  • 索引值计算 : index 索引号 大于等于 3 , 也就是显示最右侧的 图片 1 时 , 此时 将其重置为 0 , 动画执行完毕后 , 立刻重置 , 如果不重置 , 再往右侧滑动 , 就要出空白了 ;
  • 去掉过渡效果 : 一定要 去掉 ul 的过渡效果 , 取消平滑动画 , 让 ul 元素 瞬间跳转 避免无视觉卡顿 ;
  • 计算距离 : 计算新的索引对应的 向左平移距离 , 利用重 置后的 索引号 乘以容器宽度 , 计算新的平移距离 ;
javascript 复制代码
                // 无缝滚动 ( 向右滚动 ) : 判断索引号是否大于等于 3 ( 对应轮播图的 第 4 张 , 即 最后一张 有效图 之后的备用图 ) 
                // 自动播放 和 手动拖动 都会 向右滚动 
                if (index >= 3) {
                    // 核心重点 : index 索引号 等于 3 , 也就是显示最右侧的 图片 1 时 , 此时将其重置为 0 
                    //           动画执行完毕后 , 立刻重置
                    //           如果不重置 , 再往右侧滑动 , 就要出空白了
                    // 将索引号重置为 0 , 回到第一张轮播图的标记 , 实现循环无缝
                    index = 0;
                    // 去掉 ul 的过渡效果 , 取消平滑动画 , 让 ul 元素 瞬间跳转 避免无视觉卡顿
                    ul.style.transition = 'none';
                    // 计算新的索引对应的 向左平移距离 : 利用重 置后的 索引号 乘以容器宽度 , 计算新的平移距离
                    var translatex = -index * w;
                    // 让 ul 快速平移到第一张图的位置 , 完成无缝轮播的视觉衔接
                    ul.style.transform = 'translateX(' + translatex + 'px)';
                }

向左无缝滚动 : 判断索引号是否 小于 0 ( 对应向左滑动到第一张图之前的备用图 ) ;

  • 索引值计算 : 将索引号重置为 2 , 回到最后一张有效轮播图的标记 , 实现反向循环无缝
  • 去掉过渡效果 : 一定要 去掉 ul 的过渡效果 , 取消平滑动画 , 让 ul 元素 瞬间跳转 避免无视觉卡顿 ;
  • 计算距离 : 计算新的索引对应的 向左平移距离 , 利用重 置后的 索引号 乘以容器宽度 , 计算新的平移距离 ;
javascript 复制代码
                // 无缝滚动 ( 向左滚动 ) : 判断索引号是否小于 0 ( 对应向左滑动到第一张图之前的备用图 ) 
                // 只有 手动拖动 才会向左滚动
                else if (index < 0) {
                    // 将索引号重置为 2 , 回到最后一张有效轮播图的标记 , 实现反向循环无缝
                    index = 2;
                    // 去掉 ul 的过渡效果 , 取消平滑动画 , 让ul快速跳转无视觉卡顿
                    ul.style.transition = 'none';
                    // 利用重置后的索引号乘以容器宽度 , 计算新的平移距离
                    var translatex = -index * w;
                    // 让 ul 快速平移到最后一张有效图的位置 , 完成 反向 无缝轮播 的视觉衔接
                    ul.style.transform = 'translateX(' + translatex + 'px)';
                }

小圆点设置 : 小圆点 跟随 当前显示的轮播图索引 而变化 , 从 ol 中选中带有 current 类名的 li 元素 , 移除其 current 类 , 取消 上一个小圆点 的选中状态 , 找到 ol 中对应当前索引号 index 的 li 元素 , 为其添加 current 类 , 设置当前小圆点的选中状态 ;

javascript 复制代码
                // 小圆点 跟随 当前显示的轮播图索引 而变化
                // 从 ol 中选中带有 current 类名的 li 元素 , 移除其 current 类 , 取消 上一个小圆点 的选中状态
                ol.querySelector('.current').classList.remove('current');
                // 找到 ol 中对应当前索引号 index 的 li 元素 , 为其添加 current 类 , 设置当前小圆点的选中状态
                ol.children[index].classList.add('current');

代码示例 :

javascript 复制代码
            // 3. 无缝衔接滚动 : 在 轮播图 最后一张图之后 , 再 追加一张 第一张图 的备份 , 实现无缝衔接
            //      等着我们 过渡完成 之后 , 再去判断 监听过渡完成的事件 transitionend 
            //      给 ul 添加 transitionend 事件监听 , 该事件在 CSS 过渡动画完成后触发 , 用于处理 无缝滚动逻辑
            ul.addEventListener('transitionend', function() {

                // 核心轮播图 有 3 张 
                // 3 张核心图 的 右侧 , 再追加一张 第 1 张核心图 的 备份图
                // 3 张核心图 的 左侧 , 再追加一张 第 3 张核心图 的 备份图
                // 其作用是 在 处于 第 1 张核心图 位置时 , 向左滑动 , 可以看到 第 3 张核心图 的 备份图 , 避免出现空白
                //         在 处于 第 3 张核心图 位置时 , 向右滑动 , 可以看到 第 1 张核心图 的 备份图 , 避免出现空白

                // 无缝滚动 ( 向右滚动 ) : 判断索引号是否大于等于 3 ( 对应轮播图的 第 4 张 , 即 最后一张 有效图 之后的备用图 ) 
                // 自动播放 和 手动拖动 都会 向右滚动 
                if (index >= 3) {
                    // 核心重点 : index 索引号 等于 3 , 也就是显示最右侧的 图片 1 时 , 此时将其重置为 0 
                    //           动画执行完毕后 , 立刻重置
                    //           如果不重置 , 再往右侧滑动 , 就要出空白了
                    // 将索引号重置为 0 , 回到第一张轮播图的标记 , 实现循环无缝
                    index = 0;
                    // 去掉 ul 的过渡效果 , 取消平滑动画 , 让 ul 元素 瞬间跳转 避免无视觉卡顿
                    ul.style.transition = 'none';
                    // 计算新的索引对应的 向左平移距离 : 利用重 置后的 索引号 乘以容器宽度 , 计算新的平移距离
                    var translatex = -index * w;
                    // 让 ul 快速平移到第一张图的位置 , 完成无缝轮播的视觉衔接
                    ul.style.transform = 'translateX(' + translatex + 'px)';
                }

                // 无缝滚动 ( 向左滚动 ) : 判断索引号是否小于 0 ( 对应向左滑动到第一张图之前的备用图 ) 
                // 只有 手动拖动 才会向左滚动
                else if (index < 0) {
                    // 将索引号重置为 2 , 回到最后一张有效轮播图的标记 , 实现反向循环无缝
                    index = 2;
                    // 去掉 ul 的过渡效果 , 取消平滑动画 , 让ul快速跳转无视觉卡顿
                    ul.style.transition = 'none';
                    // 利用重置后的索引号乘以容器宽度 , 计算新的平移距离
                    var translatex = -index * w;
                    // 让 ul 快速平移到最后一张有效图的位置 , 完成 反向 无缝轮播 的视觉衔接
                    ul.style.transform = 'translateX(' + translatex + 'px)';
                }

                // 小圆点 跟随 当前显示的轮播图索引 而变化
                // 从 ol 中选中带有 current 类名的 li 元素 , 移除其 current 类 , 取消 上一个小圆点 的选中状态
                ol.querySelector('.current').classList.remove('current');
                // 找到 ol 中对应当前索引号 index 的 li 元素 , 为其添加 current 类 , 设置当前小圆点的选中状态
                ol.children[index].classList.add('current');
            });

6、手指滑动轮播图

手指滑动轮播图 : 本质是 ul 跟随手指移动 , 就是 移动端拖动元素 ;

  • 在 触摸元素 touchstart 事件中 , 获取手指初始坐标 ;
  • 在 触摸元素 touchmove 事件中 , 计算手指的滑动距离 , 并且移动盒子 ;
  • 在 触摸元素 touchend 事件中 , 根据移动距离去判断是 回弹 还是 切换到 上一张 / 下一张 轮播图 ;

初始变量定义 : 定义 计算过程中 需要用到的 各种变量 ;

javascript 复制代码
            // 触摸元素 touchstart :  获取手指初始坐标
            // 定义变量 startX , 用于存储手指触摸屏幕时的初始X坐标 , 初始值为 0
            var startX = 0;

            // 定义变量 moveX , 用于存储手指滑动过程中的移动距离 , 初始值为 0 ( 全局变量 , 供多个触摸事件共用 ) 
            var moveX = 0; // 后面我们会使用这个移动距离所以要定义一个全局变量

            // 定义变量flag , 用于标记手指是否发生了有效滑动 , 初始值为false
            var flag = false;

开始触摸事件 : 给 ul 添加 touchstart 事件监听 , 该事件在手指触摸到屏幕时触发 ;

  • 记录坐标 : 获取手指触摸点的页面 X 坐标 , 赋值给 startX , 记录 触摸初始位置 , 由于只关心左右滑动 , 只只需要获取 X 值坐标即可 ;
  • 清除定时器 : 手指触摸的时候清除定时器 , 停止自动轮播 , 避免自动轮播与手指滑动冲突
javascript 复制代码
            // 4.1 给 ul 添加 touchstart 事件监听 , 该事件在手指触摸到屏幕时触发
            ul.addEventListener('touchstart', function(e) {
                // 获取手指触摸点的页面 X 坐标 , 赋值给 startX , 记录 触摸初始位置
                // 由于只关心左右滑动 , 只只需要获取 X 值坐标即可 
                startX = e.targetTouches[0].pageX;
                // 手指触摸的时候清除定时器 , 停止自动轮播 , 避免自动轮播与手指滑动冲突
                clearInterval(timer);
            });

触摸移动事件 : 移动手指 touchmove 事件中 计算手指的滑动距离 , 并且移动盒子 , 给 ul 添加 touchmove 事件监听 , 该事件在手指在屏幕上滑动时持续触发 ;

  • 计算手指滑动距离 : 计算手指滑动的距离 , 当前触摸点的 X 坐标 减去 初始触摸 X 坐标 , 得到横向移动距离 ;
  • 计算元素平移距离 : ul 需要平移的总距离 , 原来的轮播位置 ( -index * w ) 加上 手指滑动的距离 , 实现跟随手指拖动 ;
  • 取消过渡效果 : 手指拖动的时候 不需要动画效果 , 取消 ul 的过渡效果 , 让 ul 跟随手指滑动无延迟 , 提升拖动体验 ;
  • 阻止默认行为 : 阻止事件的默认行为 , 防止手指滑动时触发页面的默认滚动 ( 上下/左右滚动 ) , 保证轮播图滑动的纯净性 ;
javascript 复制代码
            // 4.2 移动手指 touchmove :  计算手指的滑动距离 ,  并且移动盒子
            // 给 ul 添加 touchmove 事件监听 , 该事件在手指在屏幕上滑动时持续触发
            ul.addEventListener('touchmove', function(e) {
                // 计算手指滑动的距离 : 当前触摸点的 X 坐标 减去 初始触摸 X 坐标 , 得到横向移动距离
                moveX = e.targetTouches[0].pageX - startX;

                // 计算 ul 需要平移的总距离 : 原来的轮播位置 ( -index * w ) 加上 手指滑动的距离 , 实现跟随手指拖动
                var translatex = -index * w + moveX;

                // 手指拖动的时候 不需要动画效果 , 取消 ul 的过渡效果 , 让 ul 跟随手指滑动无延迟 , 提升拖动体验
                ul.style.transition = 'none';
                // 让 ul 平移到 计算好的位置 , 实现 跟随手指拖动 的 视觉效果
                ul.style.transform = 'translateX(' + translatex + 'px)';

                // 将 flag 标记为 true , 表示用户手指发生了有效滑动 , 后续手指离开时需要进行判断处理
                flag = true; // 如果用户手指移动过我们再去判断否则不做判断效果

                // 阻止事件的默认行为 , 防止手指滑动时触发页面的默认滚动 ( 上下/左右滚动 )  , 保证轮播图滑动的纯净性
                e.preventDefault(); // 阻止滚动屏幕的行为
            });

触摸结束事件 : 手指离开 根据移动距离去判断是 回弹 还是 切换到 上一张 / 下一张 , 给 ul 添加 touchend 事件监听 , 该事件在手指离开屏幕时触发 ;

  • 播放上一张或下一张 : 如果移动距离的 绝对值 大于 50 像素 , 判定为 有效切换 , 播放上一张或下一张 ;
  • 回弹效果 : 如果移动距离的绝对值小于等于 50 像素 , 判定为无效滑动 , 执行 回弹效果 ;
javascript 复制代码
           // 4.3 手指离开 根据移动距离去判断是 回弹 还是 切换到 上一张 / 下一张
            // 给 ul 添加 touchend 事件监听 , 该事件在手指离开屏幕时触发
            ul.addEventListener('touchend', function(e) {
                // 判断 flag 是否为 true , 仅当用户发生了 有效滑动时 , 才执行 后续判断逻辑
                if (flag) {
                    // (1) 播放上一张或下一张 : 如果移动距离的 绝对值 大于 50 像素 , 判定为 有效切换 , 播放上一张或下一张
                    // 注意 : 这里计算的是 绝对值 , 不判定 正负 
                    if (Math.abs(moveX) > 50) {
                        // 如果 moveX 大于 0 , 表示手指向右滑动 , 需要播放 上一张轮播图 , 索引号 自减 1
                        if (moveX > 0) {
                            index--;
                        } else {
                            // 如果 moveX 小于 0 , 表示手指向左滑动 , 需要播放下一张轮播图 , 索引号自增1
                            index++;
                        }
                        // 计算对应索引号的ul平移距离
                        var translatex = -index * w;
                        // 恢复ul的过渡效果 , 让轮播图切换时有平滑的动画效果
                        ul.style.transition = 'all .3s';
                        // 让ul平移到目标位置 , 完成轮播图的切换
                        ul.style.transform = 'translateX(' + translatex + 'px)';
                    } else {
                        // (2) 回弹效果 : 如果移动距离的绝对值小于等于 50 像素 , 判定为无效滑动 , 执行 回弹效果
                        // 计算 当前索引号 ( index 索引值不变 ) 对应的 ul 平移距离 ( 即原来的轮播位置 ) 
                        var translatex = -index * w;
                        // 设置较短的过渡效果 ( 0.1秒 )  , 让回弹效果更流畅快速
                        ul.style.transition = 'all .1s';
                        // 让 ul 平移回原来的轮播位置 , 实现回弹效果
                        ul.style.transform = 'translateX(' + translatex + 'px)';
                    }
                }

                // 手指离开时 , 先清除之前的定时器 ( 防止定时器叠加 ) 
                clearInterval(timer);

                // 重新开启 周期性定时器 , 恢复 自动轮播功能 , 保持 轮播的连续性
                timer = setInterval(function() {
                    // 索引号自增1 , 切换到下一张轮播图
                    index++;
                    // 计算ul需要平移的水平距离
                    var translatex = -index * w;
                    // 给ul设置过渡动画 , 实现流畅滑动
                    ul.style.transition = 'all .3s';
                    // 让ul水平平移 , 显示下一张轮播图
                    ul.style.transform = 'translateX(' + translatex + 'px)';
                }, 2000);
            });

二、代码示例 - 移动端轮播图案例


1、代码示例

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>移动端轮播图</title>
    <!-- 引入 css 初始化文件 : normalize.css 是一个跨浏览器的 CSS 样式标准化方案 , 
     核心目标是抹平不同浏览器之间的 HTML 元素默认样式差异 , 
     让页面在各种现代浏览器 ( Chrome、Firefox、Safari 等 ) 中呈现出一致的基础外观 , 
     同时避免不必要的样式重置 , 提升前端开发的效率和兼容性 ;  -->
    <link rel="stylesheet" href="css/normalize.css">

    <!-- 引入自己写的样式 , 本案例为空 -->
    <link rel="stylesheet" href="css/index.css">

    <!-- 引入自己写的脚本 , 本案例为空 -->
    <script src="js/index.js"></script>

    <style>
        body {
            /* 定义页面全局基础容器 ( body标签 ) 的样式 */
            /* 限制页面最大宽度为540px , 适配大屏手机 , 防止页面过宽导致布局变形 */
            max-width: 540px;
            /* 限制页面最小宽度为320px , 适配小屏手机 , 保证核心内容不会被挤压无法显示 */
            min-width: 320px;
            /* 给body设置1200px高度 , 撑开页面布局 , 便于查看轮播效果 , 避免高度塌陷 */
            height: 1200px;
            /* 上下外边距为0 , 左右外边距自动分配 , 实现页面在屏幕中水平居中对齐 */
            margin: 0 auto;
            /* 统一设置字体样式 : 正常字重、14px字号、1.5倍行高 , 同时指定多字体族兼顾不同系统兼容性 */
            font: normal 14px/1.5 Tahoma, "Lucida Grande", Verdana, "Microsoft Yahei", STXihei, hei;
            /* 设置页面默认文字颜色为纯黑色 */
            color: #000;
            /* 设置页面背景色为浅灰色 , 提升视觉舒适度 , 区分页面内容与背景 */
            background: #f2f2f2;
            /* 隐藏水平方向溢出的内容 , 防止出现水平滚动条 , 保证移动端布局整洁 */
            overflow-x: hidden;
            /* 清除webkit内核浏览器中 , 移动端点击元素时出现的默认高亮背景色 */
            -webkit-tap-highlight-color: transparent;
        }
        
        ul {
            /* 重置所有ul列表的默认浏览器样式 */
            /* 去除ul列表默认的项目符号 ( 圆点、数字等 )  */
            list-style: none;
            /* 去除ul列表默认的外边距 , 消除浏览器默认样式差异 */
            margin: 0;
            /* 去除ul列表默认的内边距 , 消除浏览器默认样式差异 */
            padding: 0;
        }
        
        a {
            /* 重置所有a链接的默认浏览器样式 */
            /* 去除a链接默认的下划线装饰 , 自定义链接视觉样式 */
            text-decoration: none;
            /* 设置a链接默认文字颜色为深灰色 , 统一链接视觉风格 */
            color: #222;
        }
        
        div {
            /* 统一所有div元素的盒模型计算方式 */
            /* 让元素的内边距、边框计入宽高总尺寸 , 避免传统盒模型导致的布局错乱 */
            box-sizing: border-box;
        }
        
        .focus {
            /* 定义轮播图容器 ( 类名为focus ) 的核心样式 */
            /* 开启相对定位 , 为内部子元素的绝对定位提供参考容器 ( 子元素绝对定位不会脱离该容器 )  */
            position: relative;
            /* 顶部内边距44px , 为轮播图上方预留空间 ( 通常用于放置导航栏等组件 )  */
            padding-top: 44px;
            /* 隐藏容器内部超出的内容 , 防止轮播图横向滑动时溢出显示 */
            overflow: hidden;
        }
        
        .focus img {
            /* 定义轮播图容器内所有图片的样式 */
            /* 图片宽度占满父容器 ( focus )  , 实现轮播图响应式适配容器宽度 */
            width: 100%;
        }
        
        .focus ul {
            /* 定义轮播图图片列表 ( ul ) 的样式 , 用于承载所有轮播图片 */
            /* 隐藏ul内部超出的内容 , 配合浮动实现多图横向排列不溢出 */
            overflow: hidden;
            /* 设置ul宽度为500% , 对应5张轮播图 ( 每张占20% )  , 实现多图横向并排布局 */
            width: 500%;
            /* ul向左平移自身宽度的100% , 隐藏最左侧的备用图 , 默认显示第1张有效轮播图 ( 无缝轮播核心前置处理 )  */
            margin-left: -100%;
        }
        
        .focus ul li {
            /* 定义轮播图列表中单个图片容器 ( li ) 的样式 */
            /* 开启左浮动 , 让所有li元素横向排列 , 实现多图并排展示 */
            float: left;
            /* 每个li宽度占ul的20% , 对应ul的500%宽度 , 5个li正好铺满ul实现等分 */
            width: 20%;
        }
        
        .focus ol {
            /* 定义轮播图指示器列表 ( ol ) 的样式 , 用于显示轮播图当前位置 */
            /* 开启绝对定位 , 让指示器脱离文档流 , 固定在轮播图右下角 */
            position: absolute;
            /* 距离轮播图容器底部5px , 定位指示器垂直位置 */
            bottom: 5px;
            /* 距离轮播图容器右侧5px , 定位指示器水平位置 */
            right: 5px;
            /* 去除ol列表默认的外边距 , 消除浏览器默认样式差异 */
            margin: 0;
        }
        
        .focus ol li {
            /* 定义轮播图单个指示器圆点 ( li ) 的样式 */
            /* 转换为行内块元素 , 既可以设置宽高 , 又能实现横向排列 ( 不独占一行 )  */
            display: inline-block;
            /* 设置指示器圆点的宽度为5px */
            width: 5px;
            /* 设置指示器圆点的高度为5px */
            height: 5px;
            /* 设置指示器圆点默认背景色为白色 , 与轮播图背景形成对比 */
            background-color: #fff;
            /* 去除ol列表默认的项目符号 , 保持指示器样式整洁 */
            list-style: none;
            /* 给圆点设置圆角 , 使其呈现椭圆形 ( 宽高相等时近似圆形 )  */
            border-radius: 2px;
            /* 添加过渡动画 , 所有样式变化在 0.3 秒内平滑完成 , 实现选中时的宽度渐变效果 */
            transition: all .3s;
        }
        
        .focus ol li.current {
            /* 定义轮播图当前选中状态的指示器 ( current类 ) 样式 */
            /* 选中时将指示器宽度改为15px , 与默认5px形成视觉区分 , 提示当前轮播图位置 */
            width: 15px;
        }
    </style>
    <script>
        // 监听整个窗口的load事件 , 页面所有资源 ( DOM、图片等 ) 加载完成后执行内部逻辑 , 避免DOM未加载完成获取不到元素
        window.addEventListener('load', function() {

            // 1. 获取元素 
            // 通过类选择器获取轮播图容器元素 , 赋值给变量focus , 后续操作轮播图核心依赖该容器
            var focus = document.querySelector('.focus');
            // 获取 focus 容器的 第一个子元素 ( 即承载轮播图片的ul )  , 赋值给变量 ul
            var ul = focus.children[0];
            // 获得 focus 容器的可视宽度 , 赋值给变量 w , 后续轮播图平移距离均基于该宽度计算
            var w = focus.offsetWidth;
            // 获取focus容器的第二个子元素 ( 即承载指示器的ol )  , 赋值给变量ol
            var ol = focus.children[1];


            // 2. 利用定时器自动轮播图图片
            // 定义轮播图索引号变量 index , 初始值为 0 , 用于 标记 当前显示 的轮播图位置
            var index = 0;
            // 定义定时器变量 timer , 开启一个 周期性定时器 , 每隔 2000 毫秒执行一次 滚动轮播逻辑
            var timer = setInterval(function() {
                // 索引号 自增 1 , 切换到下一张轮播图
                index++;
                // 计算 ul 需要平移的水平距离 : 负的索引号 乘以 容器宽度 , 实现 ul 向左平移对应距离
                var translatex = -index * w;
                // 给 ul 设置 过渡动画 , 所有样式变化在 0.3 秒内 平滑完成 , 实现轮播图滑动的流畅效果
                ul.style.transition = 'all .3s';
                // 通过 transform 的 translateX 属性 , 让 ul 水平平移计算好的距离 , 显示下一张轮播图
                ul.style.transform = 'translateX(' + translatex + 'px)';
            }, 2000);

            // 3. 无缝衔接滚动 : 在 轮播图 最后一张图之后 , 再 追加一张 第一张图 的备份 , 实现无缝衔接
            //      等着我们 过渡完成 之后 , 再去判断 监听过渡完成的事件 transitionend 
            //      给 ul 添加 transitionend 事件监听 , 该事件在 CSS 过渡动画完成后触发 , 用于处理 无缝滚动逻辑
            ul.addEventListener('transitionend', function() {
                // 核心轮播图 有 3 张 
                // 3 张核心图 的 右侧 , 再追加一张 第 1 张核心图 的 备份图
                // 3 张核心图 的 左侧 , 再追加一张 第 3 张核心图 的 备份图
                // 其作用是 在 处于 第 1 张核心图 位置时 , 向左滑动 , 可以看到 第 3 张核心图 的 备份图 , 避免出现空白
                //         在 处于 第 3 张核心图 位置时 , 向右滑动 , 可以看到 第 1 张核心图 的 备份图 , 避免出现空白

                // 无缝滚动 ( 向右滚动 ) : 判断索引号是否大于等于 3 ( 对应轮播图的 第 4 张 , 即 最后一张 有效图 之后的备用图 ) 
                // 自动播放 和 手动拖动 都会 向右滚动 
                if (index >= 3) {
                    // 核心重点 : index 索引号 等于 3 , 也就是显示最右侧的 图片 1 时 , 此时将其重置为 0 
                    //           动画执行完毕后 , 立刻重置
                    //           如果不重置 , 再往右侧滑动 , 就要出空白了
                    // 将索引号重置为 0 , 回到第一张轮播图的标记 , 实现循环无缝
                    index = 0;
                    // 去掉 ul 的过渡效果 , 取消平滑动画 , 让 ul 元素 瞬间跳转 避免无视觉卡顿
                    ul.style.transition = 'none';
                    // 计算新的索引对应的 向左平移距离 : 利用重 置后的 索引号 乘以容器宽度 , 计算新的平移距离
                    var translatex = -index * w;
                    // 让 ul 快速平移到第一张图的位置 , 完成无缝轮播的视觉衔接
                    ul.style.transform = 'translateX(' + translatex + 'px)';
                }

                // 无缝滚动 ( 向左滚动 ) : 判断索引号是否小于 0 ( 对应向左滑动到第一张图之前的备用图 ) 
                // 只有 手动拖动 才会向左滚动
                else if (index < 0) {
                    // 将索引号重置为 2 , 回到最后一张有效轮播图的标记 , 实现反向循环无缝
                    index = 2;
                    // 去掉 ul 的过渡效果 , 取消平滑动画 , 让ul快速跳转无视觉卡顿
                    ul.style.transition = 'none';
                    // 利用重置后的索引号乘以容器宽度 , 计算新的平移距离
                    var translatex = -index * w;
                    // 让 ul 快速平移到最后一张有效图的位置 , 完成 反向 无缝轮播 的视觉衔接
                    ul.style.transform = 'translateX(' + translatex + 'px)';
                }

                // 小圆点 跟随 当前显示的轮播图索引 而变化
                // 从 ol 中选中带有 current 类名的 li 元素 , 移除其 current 类 , 取消 上一个小圆点 的选中状态
                ol.querySelector('.current').classList.remove('current');
                // 找到 ol 中对应当前索引号 index 的 li 元素 , 为其添加 current 类 , 设置当前小圆点的选中状态
                ol.children[index].classList.add('current');
            });

            // 4. 手指滑动轮播图 : 本质是 ul 跟随手指移动 , 就是 移动端拖动元素

            // 触摸元素 touchstart :  获取手指初始坐标
            // 定义变量 startX , 用于存储手指触摸屏幕时的初始X坐标 , 初始值为 0
            var startX = 0;

            // 定义变量 moveX , 用于存储手指滑动过程中的移动距离 , 初始值为 0 ( 全局变量 , 供多个触摸事件共用 ) 
            var moveX = 0; // 后面我们会使用这个移动距离所以要定义一个全局变量

            // 定义变量flag , 用于标记手指是否发生了有效滑动 , 初始值为false
            var flag = false;

            // 4.1 给 ul 添加 touchstart 事件监听 , 该事件在手指触摸到屏幕时触发
            ul.addEventListener('touchstart', function(e) {
                // 获取手指触摸点的页面 X 坐标 , 赋值给 startX , 记录 触摸初始位置
                // 由于只关心左右滑动 , 只只需要获取 X 值坐标即可 
                startX = e.targetTouches[0].pageX;
                // 手指触摸的时候清除定时器 , 停止自动轮播 , 避免自动轮播与手指滑动冲突
                clearInterval(timer);
            });

            // 4.2 移动手指 touchmove :  计算手指的滑动距离 ,  并且移动盒子
            // 给ul添加 touchmove 事件监听 , 该事件在手指在屏幕上滑动时持续触发
            ul.addEventListener('touchmove', function(e) {
                // 计算手指滑动的距离 : 当前触摸点的 X 坐标 减去 初始触摸 X 坐标 , 得到横向移动距离
                moveX = e.targetTouches[0].pageX - startX;

                // 计算 ul 需要平移的总距离 : 原来的轮播位置 ( -index * w ) 加上 手指滑动的距离 , 实现跟随手指拖动
                var translatex = -index * w + moveX;

                // 手指拖动的时候 不需要动画效果 , 取消 ul 的过渡效果 , 让 ul 跟随手指滑动无延迟 , 提升拖动体验
                ul.style.transition = 'none';
                // 让 ul 平移到 计算好的位置 , 实现 跟随手指拖动 的 视觉效果
                ul.style.transform = 'translateX(' + translatex + 'px)';

                // 将 flag 标记为 true , 表示用户手指发生了有效滑动 , 后续手指离开时需要进行判断处理
                flag = true; // 如果用户手指移动过我们再去判断否则不做判断效果

                // 阻止事件的默认行为 , 防止手指滑动时触发页面的默认滚动 ( 上下/左右滚动 )  , 保证轮播图滑动的纯净性
                e.preventDefault(); // 阻止滚动屏幕的行为
            });

            // 4.3 手指离开 根据移动距离去判断是 回弹 还是 切换到 上一张 / 下一张
            // 给 ul 添加 touchend 事件监听 , 该事件在手指离开屏幕时触发
            ul.addEventListener('touchend', function(e) {
                // 判断 flag 是否为 true , 仅当用户发生了 有效滑动时 , 才执行 后续判断逻辑
                if (flag) {
                    // (1) 播放上一张或下一张 : 如果移动距离的 绝对值 大于 50 像素 , 判定为 有效切换 , 播放上一张或下一张
                    // 注意 : 这里计算的是 绝对值 , 不判定 正负 
                    if (Math.abs(moveX) > 50) {
                        // 如果 moveX 大于 0 , 表示手指向右滑动 , 需要播放 上一张轮播图 , 索引号 自减 1
                        if (moveX > 0) {
                            index--;
                        } else {
                            // 如果 moveX 小于 0 , 表示手指向左滑动 , 需要播放下一张轮播图 , 索引号自增1
                            index++;
                        }
                        // 计算对应索引号的ul平移距离
                        var translatex = -index * w;
                        // 恢复ul的过渡效果 , 让轮播图切换时有平滑的动画效果
                        ul.style.transition = 'all .3s';
                        // 让ul平移到目标位置 , 完成轮播图的切换
                        ul.style.transform = 'translateX(' + translatex + 'px)';
                    } else {
                        // (2) 回弹效果 : 如果移动距离的绝对值小于等于 50 像素 , 判定为无效滑动 , 执行 回弹效果
                        // 计算 当前索引号 ( index 索引值不变 ) 对应的 ul 平移距离 ( 即原来的轮播位置 ) 
                        var translatex = -index * w;
                        // 设置较短的过渡效果 ( 0.1秒 )  , 让回弹效果更流畅快速
                        ul.style.transition = 'all .1s';
                        // 让 ul 平移回原来的轮播位置 , 实现回弹效果
                        ul.style.transform = 'translateX(' + translatex + 'px)';
                    }
                }

                // 手指离开时 , 先清除之前的定时器 ( 防止定时器叠加 ) 
                clearInterval(timer);

                // 重新开启 周期性定时器 , 恢复 自动轮播功能 , 保持 轮播的连续性
                timer = setInterval(function() {
                    // 索引号自增1 , 切换到下一张轮播图
                    index++;
                    // 计算ul需要平移的水平距离
                    var translatex = -index * w;
                    // 给ul设置过渡动画 , 实现流畅滑动
                    ul.style.transition = 'all .3s';
                    // 让ul水平平移 , 显示下一张轮播图
                    ul.style.transform = 'translateX(' + translatex + 'px)';
                }, 2000);
            });
        })
    </script>
</head>

<body>

    <div class="focus">
        <!-- 轮播图 图片 -->
        <ul>
            <!-- 滚动时 该图片 不计入 索引号 -->
            <li><img src="image/focus3.jpg" alt=""></li>
            <!-- 索引号 0 -->
            <li><img src="image/focus1.jpg" alt=""></li>
            <!-- 索引号 1 -->
            <li><img src="image/focus2.jpg" alt=""></li>
            <!-- 索引号 2 -->
            <li><img src="image/focus3.jpg" alt=""></li>
            <!-- 索引号 3 -->
            <li><img src="image/focus1.jpg" alt=""></li>
        </ul>
        <!-- 右下方的小圆点按钮 -->
        <ol>
            <li class="current"></li>
            <li></li>
            <li></li>
        </ol>
    </div>

</body>

</html>

2、执行结果

相关推荐
犬大犬小2 小时前
Web 渗透:如何绕过403 Forbidden? Part I
前端·安全性测试·web 安全
2501_946244782 小时前
Flutter & OpenHarmony OA系统图片预览组件开发指南
android·javascript·flutter
AI前端老薛2 小时前
面试:了解闭包吗?
前端
xu_duo_i2 小时前
vue3+element-plus图片上传,前端压缩(纯函数,无插件)
前端·javascript·vue.js
林恒smileZAZ2 小时前
在 Web 前端实现流式 TTS 播放
前端
睡不着的可乐2 小时前
前端优化:requestAnimationFrame vs setInterval 性能对比与实战
前端
C_心欲无痕2 小时前
nodejs - npm serve
前端·npm·node.js
POLITE32 小时前
Leetcode 240. 搜索二维矩阵 II JavaScript (Day 9)
javascript·leetcode·矩阵
释怀不想释怀3 小时前
web前端crud (修改,删除)
前端