JavaScript练手小技巧:利用鼠标滚轮控制图片轮播

news2024/12/23 10:55:46

近日,在浏览网站的时候,发现了一个有意思的效果:一个图片轮播,通过上下滚动鼠标滚轮控制图片的上下切换。

于是就有了自己做一个的想法,顺带复习下鼠标滚轮事件。

鼠标滚轮事件,参考这篇文章:鼠标滚轮事件-CSDN博客

一、HTML和CSS

无论怎么样的滚动,首先要制作图片轮播的结构和样式。

HTML:

<div class="box" id="box">
    <ul class="list" id="list">
        <li><img src="../images/pic1.jpg" alt=""></li>
        <li><img src="../images/pic2.jpg" alt=""></li>
        <li><img src="../images/pic3.jpg" alt=""></li>
        <li><img src="../images/pic4.jpg" alt=""></li>
        <li><img src="../images/pic5.jpg" alt=""></li>
    </ul>   
    <div class="dots" id="dots"></div>
</div>

HTML结构很简单,就是一个 div 里面套了两个结构:图片区和控制点区。

  • 图片区 ul#list,就是一个 ul,里面有多个 li 嵌套了图片。
  • 控制点区 div#dots 没有内容,这是因为控制点要根据图片的数量(ul 的 li 个数)动态生成。

CSS:

*{
    margin: 0;
    padding: 0;
}
ul,li,ol{
    list-style: none;
}
.box{
    width: 600px;
    height: 399px;
    border:20px #000 solid;
    margin-left: auto;
    margin-right: auto;
    overflow: hidden;
    position: relative;
    margin-top: 100px;
}
.list{
    position: relative;
}
.list img{
    display: block;
}
.list li{
    width: 600px;
    height: 399px;
    overflow: hidden;
}
.box .dots{
    position: absolute;
    bottom: 20px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    background: rgba(255,255,255,0.5);
    padding: 5px;
    border-radius: 30px;
}
.box .dots span{
    display: block;
    width: 15px;
    height: 15px;
    background: #fff;
    border-radius: 50%;
    margin-left: 5px;
    margin-right: 5px;
    cursor: pointer;
}
.box .dots span.active{
    background: #f30;
}

CSS代码如上,就不分析了,反正就这样。强调两点:

  • 整个  div.box 要相对定位,约束绝对定位的控制点区 div#dots
  • ul.list 也要相对定位,因为要复制第一个图,放到最后;复制最后一个图,放到第一图的前面。复制出来的图都是绝对定位的。

二、JS

1. 为了防止重复执行滚动事件,写一个 flag,当为 true 的时候,就不执行滚动事件。默认值为 false。

let isScroll = false;

2. 根据图片的个数动态生成点(span)。为了防止过度操作 DOM,使用了  createDocumentFragment 缓存生成的span 标签。

let li = list.querySelectorAll("li");
let li_len = li.length;
let index = 0;
let wrap = document.createDocumentFragment();
// 初始化工作
for(let i = 0; i < li_len; i++){
    let span = document.createElement("span");
    span.dataset.index = i;
    if(i == 0){
        span.classList.add("active");
    }
    wrap.appendChild(span);
    span.addEventListener("click",function(){
        index = this.dataset.index;
        changePic(index);
    } );
}
dots.appendChild(wrap);

3. 上下移动图片,就是在控制图片的 transform 的 translateY 属性。

// 图片切换函数:index++
function nextPic(){
    index++;
    if( index >= li_len ){
        index = 0;
        list.style.transform = "translateY(399px)"; // 调整list位置
        document.body.offsetHeight; // 强制重绘HTML
    }
    changePic(index);
}

// 图片切换函数:index--
function prevPic(){
    index--;
    if( index < 0 ){
        index = li_len - 1;
        list.style.transform = "translateY(" + (-399*li_len) + "px)";
        document.body.offsetHeight; // 强制重绘HTML
    }
    changePic(index);
}

 4. 切换图片,就是在换图,已经更改控制点的样式。

// 切换图片
function changePic(index){
    // 点的切换
    let dotsBros = findeBros(dots_span[index]);
    dots_span[index].classList.add("active");
    dotsBros.forEach(function(item){
        item.classList.remove("active");
    });
    
    // 图片切换
    isScroll = true;
    list.style.transform = "translateY(" + (-index * 399) + "px)";
    list.style.transition = "transform 0.5s";
    document.body.offsetHeight; // 强制重绘HTML
}

5. 当动画结束的时候,就要恢复 flag 变量的值为 flase,并且去掉图片的过渡动画。

// 动画结束时,恢复初始状态
list.addEventListener("transitionend",function(){
            isScroll = false;
            list.style.transition = "none";
 });

6. 滚动事件,判断滚轮值的正负,选择上还是下滚动图片。

// 鼠标滚轮事件
box.addEventListener("wheel",function(e){
    e.preventDefault();
    let delta = e.deltaY;
    if(delta > 0 && isScroll == false ){
        nextPic();
    }else if(delta < 0 && isScroll == false){
        prevPic();
    }
},{
    passive: false
});

 完整JS代码:

let box = document.getElementById("box");
let list = document.getElementById("list");
let dots = document.getElementById("dots");
let isScroll = false;

let li = list.querySelectorAll("li");
let li_len = li.length;
let index = 0;
let wrap = document.createDocumentFragment();
// 初始化工作
for(let i = 0; i < li_len; i++){
    let span = document.createElement("span");
    span.dataset.index = i;
    if(i == 0){
        span.classList.add("active");
    }
    wrap.appendChild(span);
    span.addEventListener("click",function(){
        index = this.dataset.index;
        changePic(index);
    } );
}
dots.appendChild(wrap);
let dots_span = dots.children;
// 初始图片
let liFirst = li[0];
let liLast = li[li_len - 1];
let newLiFirst = liFirst.cloneNode(true);
let newLiLast = liLast.cloneNode(true);
list.appendChild(newLiFirst);
list.appendChild(newLiLast);
newLiLast.style.position = "absolute";
newLiLast.style.top = "-399px";
newLiLast.style.left = "0";
// 工具函数:获取兄弟节点
function findeBros(tag){
    let bros = [];
    let parent = tag.parentNode;
    for(let i = 0; i < parent.children.length; i++){
        if(parent.children[i] !== tag){
            bros.push(parent.children[i]);
        }
    }
    return bros;
}
// 图片切换函数:index++
function nextPic(){
    index++;
    if( index >= li_len ){
        index = 0;
        list.style.transform = "translateY(399px)"; // 调整list位置
        document.body.offsetHeight; // 强制重绘HTML
    }
    changePic(index);
}

    // 图片切换函数:index--
    function prevPic(){
    index--;
    if( index < 0 ){
        index = li_len - 1;
        list.style.transform = "translateY(" + (-399*li_len) + "px)";
        document.body.offsetHeight; // 强制重绘HTML
    }
    changePic(index);
}

// 切换图片
function changePic(index){
    // 点的切换
    let dotsBros = findeBros(dots_span[index]);
    dots_span[index].classList.add("active");
    dotsBros.forEach(function(item){
        item.classList.remove("active");
    });
    
    // 图片切换
    isScroll = true;
    list.style.transform = "translateY(" + (-index * 399) + "px)";
    list.style.transition = "transform 0.5s";
    document.body.offsetHeight; // 强制重绘HTML
}
// 动画结束时,恢复初始状态
list.addEventListener("transitionend",function(){
    isScroll = false;
    list.style.transition = "none";
});

// 鼠标滚轮事件
box.addEventListener("wheel",function(e){
    e.preventDefault();
    let delta = e.deltaY;
    if(delta > 0 && isScroll == false ){
        nextPic();
    }else if(delta < 0 && isScroll == false){
        prevPic();
    }
},{
    passive: false
});

                                                                                                                                                                                                                                                                                                                                                                                                                                                                            

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2116839.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue 3 + Element Plus 封装单列控制编辑的可编辑表格组件

在Web应用开发中&#xff0c;经常需要提供表格数据的编辑功能。本文将介绍如何使用Vue 3结合Element Plus库来实现一个支持单列控制编辑功能的表格&#xff0c;并通过封装组件的形式提高代码的复用性。通过本教程&#xff0c;你将学会如何构建一个具备单列控制编辑功能的表格组…

Cloudways搭建WordPress外贸独立站完整教程(1)

验证邮件发送完成后&#xff0c;就等待Cloudways的回复邮件&#xff0c;一般24小时之内就会收到激活的邮件。 Cloudways账号升级 激活成功后还需要账户升级&#xff0c;Cloudways提供了为期3天的免费试用体验。如果在试用期结束之前未绑定信用卡以升级账户&#xff0c;试用期…

UE5学习笔记21-武器的射击功能

一、创建C类 创建武器子弹的类&#xff0c;创建生产武器子弹的类&#xff0c;创建弹壳的类&#xff0c;生产武器子弹的类的父类是武器的类 创建后如图&#xff0c;ProjectileMyWeapon类(产生子弹的类)继承自weapon类&#xff0c;Projectile(子弹的类)&#xff0c;Casing(弹壳声…

Claude 3.5:如何高效辅助编程——全面入门指南

在现代编程世界中&#xff0c;AI的角色越来越重要&#xff0c;尤其是在代码生成、调试、文档生成等领域中&#xff0c;AI工具的运用让开发者可以更高效地完成任务。Claude 3.5是一个这样的AI助手&#xff0c;凭借其强大的自然语言处理能力&#xff0c;在编程中提供了大量的支持…

Sui Narwhal and Tusk 共识协议笔记

一、Overwiew [ 整体流程: Client提交transaction到Narwhal Mempool。(Narwhal Mempool由一组worker和一个primary组成) Mempool接收到的Transaction->以Certificate的形式进行广播 由worker将交易打包为Batch,worker将Batch的hash发送给primary primary上运行了mempo…

mysql笔记4(数据类型)

数据库的数据类型应该是数据库架构师(DBA)和产品经理沟通后依据公司的项目、业务而定的&#xff0c;而且会不停地变化。数据类型的选择方面没有一个统一的标准&#xff0c;但是应该符合业务、项目的逻辑标准。 菜鸟教程 Mysql 数据类型 文章目录 1. int类型2. 浮点数3. 定点数4…

C# Dotfuscator加密dll设置流程

按照以下步骤处理后&#xff0c;反编译基本只能看到函数名&#xff0c;看不到源代码 1.Input 2.Setting 3.Rename 4.Rename 5.Control Flow 6.String Encryption 7.Output

【stata】自写命令分享dynamic_est,一键生成dynamic effect

1. 命令简介 dynamic_est 是一个用于可视化动态效应&#xff08;dynamic effect&#xff09;的工具。它特别适用于事件研究&#xff08;event study&#xff09;或双重差分&#xff08;Difference-in-Differences, DID&#xff09;分析。通过一句命令即可展示动态效应&#xf…

EasyPlayer.js网页H5 Web js播放器能力合集

最近遇到一个需求&#xff0c;要求做一款播放器&#xff0c;发现能力上跟EasyPlayer.js基本一致&#xff0c;满足要求&#xff1a; 需求 功性能 分类 需求描述 功能 预览 分屏模式 单分屏&#xff08;单屏/全屏&#xff09; 多分屏&#xff08;2*2&#xff09; 多分屏…

JVM面试(七)G1垃圾收集器剖析

概述 上一章我们说了&#xff0c;G1收集器&#xff0c;它属于里程碑式的发展&#xff0c;开创了面向局部收集垃圾的概念。专门针对多核处理器以及大内存的机器。在JDK9中&#xff0c;更是呗指定为官方的GC收集器。满足高吞吐的通知满足GC的STW停顿时间尽可能的短。 虽然现在我…

恶意代码分析-Lab01-01

实验一 这个实验使用Lab01-01.exe和Lab01-01.d文件,使用本章描述的工具和技术来获取关于这些文件的信息。 问题: 将文件上传至 http:/www.VirusTotal.com/进行分析并查看报告。文件匹配到了已有的反病毒软件特征吗?这些文件是什么时候编译的?这两个文件中是否存在迹象说明它…

如何在docker容器中导入.sql文件

一、准备工作 确保容器运行&#xff1a; 首先确认包含 MySQL 服务的 Docker 容器正在运行。可以通过 docker ps 命令查看正在运行的容器列表。如果容器未运行&#xff0c;使用 docker start [container_id] 命令启动容器。 准备数据库文件&#xff1a; 将需要导入的数据库文件&…

VMware安装Ubuntu虚拟机

Ubuntu镜像下载 https://ubuntu.com/download/desktop 创建虚拟机 1.典型配置 2.稍后安装操作系统 3.选择操作系统&#xff0c;Linux&#xff0c;ubuntu64位 3.设置虚拟机名称和安装位置 4.磁盘大小&#xff0c;存储为单个文件 安装系统 1.选择镜像 2.开启虚拟机 2.安装Ub…

CTFHub技能树-Git泄漏-Log

目录 一、前提知识 1.git泄漏原理 ​编辑 2.git文件泄漏造成后果 3.利用方法 (1) GitHack是一个.git泄露利用脚本&#xff0c;通过泄露的.git文件夹下的文件&#xff0c;还原重建工程源代码。渗透测试人员、攻击者&#xff0c;可以进一步审计代码&#xff0c;挖掘&#x…

【重学 MySQL】十七、比较运算符的使用

【重学 MySQL】十七、比较运算符的使用 **等于&#xff08;&#xff09;**基本用法示例注意事项结论 **安全等于运算符&#xff08;<>&#xff09;****不等于&#xff08;<> 或 !&#xff09;**示例注意事项 **大于&#xff08;>&#xff09;、大于等于&#xf…

傅里叶级数,傅里叶变换

先读文章&#xff1a;傅里叶分析之掐死教程&#xff08;完整版&#xff09;更新于2014.06.06 - 知乎 (zhihu.com) 傅里叶级数 一、内容&#xff1a;每个周期性函数都可以表示为无穷多个不同频率的正弦函数的叠加。 二、公式&#xff1a; 三、从时域到频域所保留的三点信息&…

修改Anaconda中JupterLab的默认文件存储路径

安装好Anaconda后&#xff0c;使用JupterLab创建的文件会默认存储在C盘&#xff0c;每次打开业都是打开C盘&#xff0c;可以按照如下步骤修改默认存储路径 1.点击开始然后打开anconda prompt。 2.打开命令行输入 jupyter notebook --generate-config &#xff0c;点击回车&…

MySQL——表操作

目录 一、创建表 二、查看表 2.1 查看表中某成员的数据 2.2 查看整个表中的表成员 2.3 查看创建表时的句柄 三、修改表 alter 3.1 重命名 rename 3.2 新增一列 add 3.3 更改列属性 modify 3.4 更改列名称 change 3.5 删除某列 上一篇博客介绍了库的操作&#xff0c;…

零基础快速上手HarmonyOS ArkTS开发5---从简单的页面开始2---使用List组件构建列表、Grid组件构建网格布局

接着零基础快速上手HarmonyOS ArkTS开发4---从简单的页面开始继续往下学习页面布局的知识。最近发现之前学习这一章节的内容在官方已经被下了&#xff0c;替换成了另外一个案例了&#xff08;华为开发者学堂&#xff09;&#xff1a; 而且整个视频的风格也不一样了&#xff0c;…

DBeaver 24.0 高阶用法

DBeaver 24.0 高阶用法 文章目录 DBeaver 24.0 高阶用法DBeaver 介绍功能一、元数据搜索功能二、仪表盘显示功能三、ER图功能四、导出数据最后 DBeaver 介绍 DBeaver 确实是一款功能强大的通用数据库管理工具&#xff0c;适合所有需要以专业方式处理数据的用户。它不仅提供了直…