图像滑块对比功能的开发记录
背景介绍
最近,公司需要开发一款在线图像压缩工具,其中的一个关键功能是让用户直观地比较压缩前后的图像效果。因此,我们设计了一个对比组件,它允许用户通过拖动滑块,动态调整两张图像的显示区域,从而清晰地看到压缩前后的差异。
目标效果
- 两张图片堆叠放置,一张始终可见,另一张可调整可见范围。
- 通过滑块拖动,控制上层图片的显示区域。
- 适配 PC 和移动端,提供流畅的交互体验。
效果如图:
开发思路
结构设计
- 创建一个外层容器,用于包裹两张图片和滑块。
- 底层图片(原始图像)始终可见。
- 顶层图片(优化后图像)放置在上方,并使用 clip-path 控制其显示范围。
- 滑块(拖动条) 用于调整顶层图片的可见区域。
<div class="image-change-block"><div class="desc-container"><div class="before-desc">BEFORE (827 KB)</div><div class="after-desc">AFTER (94 KB)</div></div><img src="after.jpg" class="new-img" /><div class="clip-container"><img src="before.jpg" class="old-img" /></div><div class="handle-container"><div class="bar-btn" id="barBtn"></div><div class="bar-line" id="barLine"></div></div>
</div>
样式布局
- 两张图片:底层图片 position: absolute; 覆盖整个容器,顶层图片使用 clip-path 或 width 控制显示区域。
- 滑块样式:自定义 div + 伪元素 作为滑块,并放在 absolute 位置。
.image-change-block {position: relative;max-width: 44rem;overflow: hidden;border-radius: 1.25rem;
}.desc-container {top: 1.25rem;position: absolute;display: flex;align-items: center;justify-content: space-between;flex-wrap: wrap;width: 100%;padding: 0 1.25rem;gap: 0.3125rem;
}.after-desc,
.before-desc {background-color: #000000;opacity: 0.6;color: #fff;border-radius: 0.25rem;z-index: 10;font-size: var(--global--font-size-sm);padding: 0.3125rem 1.5rem;
}.old-img,
.new-img {width: 100%;height: 100%;object-fit: cover;display: block;
}.clip-container {position: absolute;top: 0;left: 0;width: 100%;height: 100%;overflow: hidden;
}.old-img {position: absolute;top: 0;left: 0;width: 100%;height: 100%;clip-path: inset(0 50% 0 0);transition: clip-path 0.01s ease;
}.handle-container {position: absolute;top: 0;left: 0;height: 100%;width: 100%;pointer-events: none;
}.bar-btn {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);width: 2rem;height: 2rem;border-radius: 50%;pointer-events: all;cursor: ew-resize;z-index: 2;
}.bar-line {position: absolute;top: 0;left: 50%;height: 100%;width: 3px;background-color: var(--theme-green-color);z-index: 1;
}.bar-btn::before {width: 28px;height: 28px;content: "";cursor: ew-resize;background: #00d4c9;position: absolute;left: 50%;top: 50%;transform: translate(-45%, -50%);display: block;border-radius: 50%;box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);z-index: 1;
}.bar-btn::after {content: "";background: var(--theme-green-color);width: 3px;height: 100%;position: absolute;left: 50%;top: 0;box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
交互逻辑
封装一个兼容 PC 和移动端的拖拽对比函数,通过传入对应的 dom 实现鼠标或手指拖动滑块时图像的对比。
initClip({barBtn: document.querySelector(`.bar-btn`),barLine: document.querySelector(`.bar-line`),clipContainer: document.querySelector(`.clip-container`),oldImg: document.querySelector(`.old-img`),
});/*** 初始化通过剪裁实现图像对比的功能* @param {Object} doms - 包含所需DOM元素的对象* - barBtn: 滑动按钮元素* - barLine: 滑动线条元素* - clipContainer: 剪裁容器元素* - oldImg: 被剪裁的图片元素*/
function initClip(doms) {// 解构赋值获取所需的DOM元素const { barBtn, barLine, clipContainer, oldImg } = doms;// 定义变量以跟踪鼠标或触摸是否在拖动let isDragging = false;let isMDragging = false;/*** 更新图片剪裁位置* @param {number} x - 鼠标或触摸在剪裁容器上的x坐标*/function updateImageClip(x) {// 计算剪裁容器的宽度const containerWidth = clipContainer.offsetWidth;// 计算并限制剪裁的百分比const percent = Math.min(Math.max(x / containerWidth, 0), 1);// 更新图片的剪裁路径oldImg.style.clipPath = `inset(0 ${100 - percent * 100}% 0 0)`;// 更新滑动按钮和线条的位置barBtn.style.left = `${percent * 100}%`;barLine.style.left = `${percent * 100}%`;}// 添加鼠标按下事件监听器到滑动按钮barBtn.addEventListener("mousedown", (e) => {// 开始拖动并阻止默认行为isDragging = true;e.preventDefault();});// 添加鼠标抬起事件监听器到文档document.addEventListener("mouseup", () => {// 结束拖动isDragging = false;});// 添加鼠标移动事件监听器到文档document.addEventListener("mousemove", (e) => {// 如果正在拖动,则更新图片剪裁if (isDragging) {const x = e.clientX - clipContainer.getBoundingClientRect().left;updateImageClip(x);}});// 添加点击事件监听器到剪裁容器clipContainer.addEventListener("click", (e) => {// 点击时更新图片剪裁const x = e.clientX - clipContainer.getBoundingClientRect().left;updateImageClip(x);});// 添加触摸开始事件监听器到滑动按钮barBtn.addEventListener("touchstart", (e) => {// 开始拖动并阻止默认行为isMDragging = true;e.preventDefault();});// 添加触摸结束事件监听器到文档document.addEventListener("touchend", () => {// 结束拖动isMDragging = false;});// 添加触摸移动事件监听器到文档document.addEventListener("touchmove", (e) => {// 如果正在拖动,则更新图片剪裁if (isMDragging) {const touch = e.touches[0];const x = touch.clientX - clipContainer.getBoundingClientRect().left;updateImageClip(x);}});
}
总结
这个滑块对比组件利用 clip-path 来裁剪图像,并结合鼠标和触摸事件监听,实现了流畅的交互体验。它不仅适用于图像压缩前后的对比,还可以扩展到滤镜效果、照片修复等其他图像对比场景。在实际开发中,我们可以根据 UI 需求,进一步优化滑块的样式、动画效果,以及提升移动端的操作体验。
原文链接
图像滑块对比功能的开发记录
相关文章:

图像滑块对比功能的开发记录
背景介绍 最近,公司需要开发一款在线图像压缩工具,其中的一个关键功能是让用户直观地比较压缩前后的图像效果。因此,我们设计了一个对比组件,它允许用户通过拖动滑块,动态调整两张图像的显示区域,从而清晰…...
【计算机网络】Socket
Socket 是网络通信的核心技术之一,充当应用程序与网络协议栈之间的接口。 1. Socket 定义 Socket(套接字)是操作系统提供的 网络通信抽象层,允许应用程序通过标准接口(如 TCP/IP 或 UDP)进行数据传输。它…...
Electron应用中获取设备唯一ID和系统信息
让我创建一篇关于如何在Electron应用中获取设备唯一ID和系统信息,并在登录时使用这些信息的博客文章。我将确保步骤明确、条理清晰,适合初学者和有经验的开发者。 这篇博客应包含以下部分: 介绍 - 为什么需要获取设备信息前提条件和安装依赖…...

文件上传漏洞:upload-labs靶场11-20
目录 pass-11 pass-12 pass-13 pass-14 pass-15 pass-16 pass-17 pass-18 pass-19 pass-20 pass-11 分析源代码 ,发现上传文件的存放路径可控 if(isset($_POST[submit])){$ext_arr array(jpg,png,gif);$file_ext substr($_FILES[upload_file][name],st…...

国产化板卡设计原理图:2330-基于FMC接口的JFM7K325T PCIeX4 3U PXIe接口卡
基于FMC接口的JFM7K325T PCIeX4 3U PXIe接口卡 一、板卡概述 本板卡基于 FPGAJFM7K325T 芯片,pin_to_pin兼容FPGAXC7K410T-2FFG900 ,支持PCIeX8、64bit DDR3容量2GByte,HPC的FMC连接器,板卡支持PXIE标准协议,其中XJ3…...

使用Open WebUI下载的模型文件(Model)默认存放在哪里?
🏡作者主页:点击! 🤖Ollama部署LLM专栏:点击! ⏰️创作时间:2025年2月21日21点21分 🀄️文章质量:95分 文章目录 使用CMD安装存放位置 默认存放路径 Open WebUI下…...

FPGA 配置原理
用户编程控制的FPGA 是通过加载比特位流配置内部的存储单元实现的。该存储单元就是所谓的配置单元,它必须在器件上电后进行配置,从而设置查找表(LUT)的属性、连线方式、IOB 电压标准和其它的用户设计。 1.配置帧 以Xilinx 公司的…...

企业级虚拟化数据库基础平台自动化部署项目
一、项目简介及准备工作 1.1.虚拟化平台简介 1.1.1.ESXi 8 是什么? 定义: ESXi 8 是 VMware 推出的最新版本 裸机虚拟化管理程序(Hypervisor),属于 VMware vSphere 产品线的核心组件。 核心功能: 在物理…...
关于elementui的时间组件与后端时间和oracle数据库时间的对应格式
前端: <el-date-pickerv-model"formInline.startTime"type"date"value-format"yyyy-MM-dd"placeholder"选择日期"> </el-date-picker> 后端: private String startTime; private String endTime…...

一周学会Flask3 Python Web开发-WTForms表单验证
锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 我们可以通过WTForms表单类属性的validators属性来实现表单验证。 常用的WTForms验证器 验证器说明DataRequired(messageNo…...

qt open3dBPA重建
qt open3dBPA重建 效果展示二、流程三、代码效果展示 二、流程 创建动作,链接到槽函数,并把动作放置菜单栏 参照前文 三、代码 1、槽函数实现 void on_actionBPA_triggered();//bpa重建 void MainWindow::...
Unity游戏开发中的网格简化与LOD技术(Mesh Simplification LOD)
在Unity游戏开发中,网格简化(Mesh Simplification)和LOD(Level of Detail)技术是优化渲染性能的关键手段,尤其在处理复杂场景和高精度模型时至关重要。以下是一套系统的实现方案与优化策略: 一、…...

基于YOLO11深度学习的运动品牌LOGO检测与识别系统【python源码+Pyqt5界面+数据集+训练代码】
《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…...

纯html文件实现目录和文档关联
目录结构 效果图 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>项目结题报告</title><style lang"scss">::-webkit-scrollbar {width: 6px;height: 6px;}::-webkit-scro…...
C# | 委托 | 事件 | 异步
委托(Delegate)和事件(Event) 在C#和C中,委托(Delegate)与事件(Event)以及函数对象(Function Object)是实现回调机制或传递行为的重要工具。虽然…...

数据结构——顺序表与链表
1. 基础介绍 1、线性结构: 如果一个数据元素序列满足: (1)除第一个和最后一个数据元素外,每个数据元素只有一个前驱数据元素和一个后继数据元素; (2)第一个数据元素没有前驱数据…...

【uniapp】图片添加canvas水印
目录 需求&背景实现地理位置添加水印 ios补充 需求&背景 需求:拍照后给图片添加水印, 水印包含经纬度、用户信息、公司logo等信息。 效果图: 方案:使用canvas添加水印。 具体实现:上传图片组件是项目里现有的ÿ…...
ElementUI 级联选择器el-cascader启用选择任意一级选项,选中后关闭下拉框
1、启用选择任意一级选项 在 el-cascader 标签上加上配置项: :props"{ checkStrictly: true }"例如: <el-cascaderref"selectedArrRef"v-model"selectedArr":options"optionsList":props"{ checkStri…...

【音视频】ffplay常用命令
一、 ffplay常用命令 -x width:强制显示宽度-y height:强制显示高度 强制以 640*360的宽高显示 ffplay 2.mp4 -x 640 -y 360 效果如下 -fs 全屏显示 ffplay -fs 2.mp4效果如下: -an 禁用音频(不播放声音)-vn 禁…...
5人3小时复刻Manus?开源OpenManus项目全解剖,我的DeepSeek股票报告这样诞生
大家好,我是大 F,深耕AI算法十余年,互联网大厂技术岗。分享AI算法干货、技术心得。 更多文章可关注《大模型理论和实战》、《DeepSeek技术解析和实战》,一起探索技术的无限可能! OpenManus是什么 1. 项目背景 OpenManus 是由 MetaGPT 核心团队仅用 3 小时复刻而成的开源…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准
城市路内停车管理常因行道树遮挡、高位设备盲区等问题,导致车牌识别率低、逃费率高,传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法,正成为破局关键。该设备安装于车位侧方0.5-0.7米高度,直接规避树枝遮…...

Linux操作系统共享Windows操作系统的文件
目录 一、共享文件 二、挂载 一、共享文件 点击虚拟机选项-设置 点击选项,设置文件夹共享为总是启用,点击添加,可添加需要共享的文件夹 查询是否共享成功 ls /mnt/hgfs 如果显示Download(这是我共享的文件夹)&…...