图像滑块对比功能的开发记录
背景介绍
最近,公司需要开发一款在线图像压缩工具,其中的一个关键功能是让用户直观地比较压缩前后的图像效果。因此,我们设计了一个对比组件,它允许用户通过拖动滑块,动态调整两张图像的显示区域,从而清晰地看到压缩前后的差异。
目标效果
- 两张图片堆叠放置,一张始终可见,另一张可调整可见范围。
- 通过滑块拖动,控制上层图片的显示区域。
- 适配 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 需求,进一步优化滑块的样式、动画效果,以及提升移动端的操作体验。
原文链接
图像滑块对比功能的开发记录
相关文章:
图像滑块对比功能的开发记录
背景介绍 最近,公司需要开发一款在线图像压缩工具,其中的一个关键功能是让用户直观地比较压缩前后的图像效果。因此,我们设计了一个对比组件,它允许用户通过拖动滑块,动态调整两张图像的显示区域,从而清晰…...
电商行业门店管理软件架构设计与数据可视化实践
一、行业痛点与核心诉求 在电商多平台运营成为主流的背景下,企业普遍面临三大管理难题: 数据碎片化:某头部服饰品牌2023年运营报告显示,其分布在8个平台的162家门店,日均产生23万条订单数据,但财务部门需要5个工作日才能完成跨平台利润核算。成本核算失真:行业调研…...
基于Arcgis的python脚本实现相邻矢量面的高度字段取平均值
文章目录 背景效果实现逻辑步骤1、准备数据2、python脚本3、执行通过脚本工具箱来执行背景 在地理信息系统(GIS)数据处理或三维建模等实际应用场景中,我们常常会遇到需要对矢量面数据进行精细化处理的需求。其中一个常见的任务便是对相邻的矢量面中的高度字段开展特定操作。…...
基于uniapp的蓝牙打印功能(佳博打印机已测试)
相关步骤 1.蓝牙打印与低功耗打印的区别2.蓝牙打印流程2.1 搜索蓝牙2.2 连接蓝牙 3.连接蓝牙设备4.获取服务5.写入命令源码gbk.jsglobalindex.ts 1.蓝牙打印与低功耗打印的区别 低功耗蓝牙是一种无线、低功耗个人局域网,运行在 2.4 GHz ISM 频段 1、低功耗蓝牙能够…...
Golang的网络流量控制
# Golang的网络流量控制 什么是网络流量控制? 网络流量控制是指针对网络数据传输过程中的流量进行管理和调控的一种技术手段。通过网络流量控制,我们可以对网络中的数据传输速率、带宽使用情况、数据包丢失率等进行监控和调整,以达到优化网络…...
在Spring Boot + MyBatis中优雅处理多表数据清洗:基于XML的配置化方案
问题背景 在实际业务中,我们常会遇到数据冗余问题。例如,一个公司表(sys_company)中存在多条相同公司名的记录,但只有一条有效(del_flag0),其余需要删除。删除前需将关联表…...
Python教程(一):基本语法、流程控制、数据容器
Python(一) 文章目录 Python(一)一、基础语法二、数据类型2.1 字符串2.2 空值2.3 类型转换&运算符 三、流程控制3.1 条件判断3.2 循环3.2.1 while循环3.2.2 for循环 四、数据结构4.1 字符串str4.1.1 字符串的格式化输出4.1.1.…...
Spring Boot 3.x 核心注解详解与最佳实践
Spring Boot 3.x 核心注解详解与最佳实践 前言 随着Spring Boot 3.x的正式发布,这个基于Spring Framework 6的里程碑版本带来了诸多新特性。本文将深入剖析Spring Boot 3.x的核心注解体系,结合代码示例讲解其作用及使用场景,助您快速掌握新…...
【AI深度学习基础】PyTorch初探
引言 PyTorch 是由 Facebook 开源的深度学习框架,专门针对 GPU 加速的深度神经网络编程,它的核心概念包括张量(Tensor)、计算图和自动求导机制。PyTorch作为Facebook开源的深度学习框架,凭借其动态计算图和直观的API设…...
Windows下安装VMware Workstation 17并设置支持MacOS
VMware Workstation 17 介绍 VMware Workstation 17 是 VMware 公司推出的一款强大的桌面虚拟化软件,适用于 Windows 、 Linux 和FreeBSD等操作系统。它允许用户在单一物理计算机上创建、运行和管理多个虚拟机(VM),每个虚拟机都可…...
Mysql-主从搭建如何指定库表同步以及新增库表同步
背景: 当主库数据量过大,从库仅需要同步A库的所有表,并且在后续运行中,又提出需要在从库新增B库的users表进行同步。本文会详细列出过程与具体命令,并告诉你其中的深坑! 步骤一: 修改从库参数…...
爬虫逆向:脱壳工具Youpk的使用详解
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 1. Youpk 简介1.1 Youpk介绍1.2 Youpk支持场景1.3 Youpk基本流程1.4 使用 Youpk 脱壳步骤1.5 常用的脱壳工具对比2. Youpk 的安装与使用2.1 安装 Youpk2.2 使用 Youpk 脱壳3. 脱壳后的 Dex 文件分析3.1 使用 JADX 反编译…...
UE4 组件 (对话组件)
制作一个可以生成对话气泡,显示对话台词的简单组件。这个组件要的变量:台词(外部传入)。功能:开始对话(生成气泡UI) ,结束对话。 一、对话组件创建 二、开始对话事件 1、注意这里获…...
LeetCode 2588.统计美丽子数组数目:前缀和 + 位运算(异或) + 哈希表
【LetMeFly】2588.统计美丽子数组数目:前缀和 位运算(异或) 哈希表 力扣题目链接:https://leetcode.cn/problems/count-the-number-of-beautiful-subarrays/ 给你一个下标从 0 开始的整数数组nums 。每次操作中,你可以: 选择…...
blender看不到导入的模型
参考:blender 快捷键 常见问题_blender材质预览快捷键-CSDN博客 方法一:视图-裁剪起点,设置一个很大的值 方法二:选中所有对象,对齐视图-视图对齐活动项-选择一个视图...
【慕课网wiki项目学习笔记01】Spring Boot 项目搭建
2-2 新建SpringBoot项目 一、创建SpringBoot项目 (1)在SpringBoot官网创建 (2.1)在 IDEA 中创建 Group:公司名 Artifact:项目名 创建成功后开始下载Maven依赖(选择右下角的Import Changes&…...
后端架构模式之-BFF(Backend-For-Frontend)
Backend-for-Frontend(BFF) 的概念与意义 1. 什么是 Backend-for-Frontend(BFF)? Backend-for-Frontend(简称 BFF)是一种后端架构模式,它为特定的前端应用(Web、移动端…...
【高分论文密码】AI大模型和R语言的全类型科研图形绘制,从画图、标注、改图、美化、组合、排序分解科研绘图每个步骤
在科研成果竞争日益激烈的当下,「一图胜千言」已成为高水平SCI期刊的硬性门槛——数据显示很多情况的拒稿与图表质量直接相关。科研人员普遍面临的工具效率低、设计规范缺失、多维数据呈现难等痛点,因此科研绘图已成为成果撰写中的至关重要的一个环节&am…...
vue3-pc-template后台管理之角色管理与功能权限配置实践
在开发企业级应用时,权限控制无疑是至关重要且不可或缺的一部分。合理的权限控制不仅能够有效保障系统的安全性,还能确保不同用户角色在系统中拥有合适的操作权限,从而提高系统的使用效率和稳定性。本文将详细介绍如何在 Vue3 项目中实现功能…...
Android Flow 示例
在Android开发的世界里,处理异步数据流一直是一个挑战。随着Kotlin的流行,Flow作为Kotlin协程库的一部分,为开发者提供了一种全新的方式来处理这些问题。今天,我将深入探讨Flow的设计理念,并通过具体的例子展示如何在实…...
前端文件加载耗时过长解决方案
从你的 Network (网络) 面板 看到,许多 JS 文件的加载时间较长(1~2秒),可能的原因如下: ✅ 可能的原因 1. 过多的 JS 请求(多个小文件加载) 你当前页面加载了很多小 JS 文件(addSi…...
Visual Studio 2022新建c语言项目的详细步骤
步骤1:点击创建新项目 步骤2:到了项目模板 --> 选择“控制台应用” (在window终端运行代码。默认打印"Hello World") --> 点击 “下一步” 步骤3:到了配置新项目模块 --> 输入“项目名称” --> 更改“位置”路径&…...
物联网系统搭建
实验项目名称 构建物联网系统 实验目的 掌握物联网系统的一般构建方法。 实验要求: 1.构建物联网系统,实现前后端的交互。 实验内容: CS模式MQTT(不带数据分析处理功能) 实现智能设备与应用客户端的交…...
PostgreSQL中的事务隔离
1. 事务隔离的概念 在数据库管理系统中,事务隔离是一项重要的功能,它能确保在并发访问数据库时事务之间能够独立运行,不会相互干扰。数据库系统通常支持不同级别的事务隔离,用来满足不同应用程序之间的需求。 2. 事务隔离的种类…...
嵌入式硬件设计SPI时需要注意什么?
嵌入式硬件设计SPI时需要注意什么? 1. 硬件设计注意事项 关键点注意事项1. 信号完整性- 缩短SCK、MOSI、MISO的走线长度,避免反射干扰。- 使用屏蔽线或差分信号(高速场景)。- 阻抗匹配(特别是高频信号,如50Ω端接)。2. 电源与地线- 电源去耦:每个SPI芯片的VCC附近放置0…...
mysql新手常见问题解决方法总结
1. 安装与配置问题 1.1 无法安装MySQL Server MySQL Server安装失败是新手常见的问题之一,以下是具体原因及解决方案: 系统要求不满足:MySQL对操作系统有最低版本要求,如Windows 7 SP1及以上、macOS 10.13及以上。若系统版本过…...
Unity3D 资源加载与卸载策略详解
前言 在Unity3D开发中,资源加载与卸载(Asset Loading & Unloading)是优化游戏性能、减少内存占用、提升用户体验的关键环节。本文将详细探讨Unity3D中的资源加载与卸载策略,并提供相关的技术详解和代码实现。 对惹ÿ…...
AcWing 蓝桥杯集训·每日一题2025·5526. 平衡细菌
5526. 平衡细菌 题意 给定一个序列 ( a i ) (a_i) (ai),每次操作可以选择一个位置 (p),令从 ( a p ) (a_p) (ap) 开始的每个数都加上一个以 (1) 或者 (-1) 为公差的从 ( 1 / − 1 ) (1 / -1) (1/−1) 开始的等差数列。求最小化让序列归零的操作…...
Android15请求动态申请存储权限完整示例
效果: 1.修改AndroidManifest.xml增加如下内容: <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-perm...
UniApp如何判断平台的多种方法(2025最新指南)
摘要:在UniApp跨平台开发中,精准判断运行环境是实现多端差异化的关键。本文将介绍6种判断平台的实用方法,涵盖编译时与运行时场景,助你轻松处理多端兼容问题。 一、为什么需要判断平台? 在UniApp跨平台开发中…...
