图像滑块对比功能的开发记录

背景介绍

最近,公司需要开发一款在线图像压缩工具,其中的一个关键功能是让用户直观地比较压缩前后的图像效果。因此,我们设计了一个对比组件,它允许用户通过拖动滑块,动态调整两张图像的显示区域,从而清晰地看到压缩前后的差异。

目标效果

  • 两张图片堆叠放置,一张始终可见,另一张可调整可见范围。
  • 通过滑块拖动,控制上层图片的显示区域。
  • 适配 PC 和移动端,提供流畅的交互体验。

效果如图:

开发思路

结构设计

  1. 创建一个外层容器,用于包裹两张图片和滑块。
  2. 底层图片(原始图像)始终可见。
  3. 顶层图片(优化后图像)放置在上方,并使用 clip-path 控制其显示范围。
  4. 滑块(拖动条) 用于调整顶层图片的可见区域。
<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 需求,进一步优化滑块的样式、动画效果,以及提升移动端的操作体验。

原文链接

图像滑块对比功能的开发记录

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

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

相关文章

tcc编译器教程2 编译lua解释器

本文主要介绍了使用tcc编译器编译lua解释器源码。 1 介绍 lua是一门编程语言,开源且源码很容易编译,我平时用来测试C语言编程环境时经常使用。一般能编译成功就说明编程环境设置正常。下面用之前设置好的tcc编程环境进行测试。 2 获取源码 我一般有保留多个版本的lua源码进…

Unity DOTS从入门到精通之 自定义Authoring类

文章目录 前言安装 DOTS 包什么是Authoring1. 实体组件2. Authoring类 前言 DOTS&#xff08;面向数据的技术堆栈&#xff09;是一套由 Unity 提供支持的技术&#xff0c;用于提供高性能游戏开发解决方案&#xff0c;特别适合需要处理大量数据的游戏&#xff0c;例如大型开放世…

comctl32!ListView_OnSetItem函数分析LISTSUBITEM结构中的image表示图标位置

第一部分&#xff1a; BOOL ListView_SetSubItem(LV* plv, const LV_ITEM* plvi) { LISTSUBITEM lsi; BOOL fChanged FALSE; int i; int idpa; HDPA hdpa; if (plvi->mask & ~(LVIF_DI_SETITEM | LVIF_TEXT | LVIF_IMAGE | LVIF_STATE)) { …

【算法】大数据查重

大数据查重 哈希表 找出第一个出现重复的数字 || 找所有重复出现的数字 #include <iostream> #include <vector> #include <unordered_map> #include <unordered_set> #include <stdlib.h> #include <time.h> #include <string> …

模型微调-基于LLaMA-Factory进行微调的一个简单案例

模型微调-基于LLaMA-Factory进行微调的一个简单案例 1. 租用云计算资源2. 拉取 LLaMa-Factory3. 安装依赖环境4. 启动 LLaMa-Factory 界面5. 从 Huggingface 下载模型6. 模型验证7. 模型微调 1. 租用云计算资源 以下示例基于 AutoDL 云计算资源。 在云计算平台选择可用的云计…

【单片机】ARM 处理器简介

ARM 公司简介 ARM&#xff08;Advanced RISC Machine&#xff09; 是英国 ARM 公司&#xff08;原 Acorn RISC Machine&#xff09; 开发的一种精简指令集&#xff08;RISC&#xff09; 处理器架构。ARM 处理器因其低功耗、高性能、广泛适用性&#xff0c;成为嵌入式系统、移动…

springboot的实体类字段校验的分组校验

分组校验&#xff08;Group Validation&#xff09;允许在不同的场景下对同一个实体类应用不同的校验规则。例如&#xff0c;在新增数据和更新数据时&#xff0c;可能需要对某些字段的校验规则进行调整。以下是分组校验的具体实现步骤&#xff1a; 一、定义分组接口 创建空的标…

vue3,Element Plus中隐藏树el-tree滚动条

el-tree&#xff0c;节点过多&#xff0c;默认会出现垂直滚动条&#xff0c;显得不美观 可以使用隐藏组件 el-scrollbar 将 el-tree 包裹&#xff0c;就可以隐藏垂直滚动条 <el-scrollbar> <el-tree> ... </el-tree> </el-scrollbar> /* 滚动条禁用鼠…

mysql练习

创建数据库db_ck&#xff0c;再创建表t_hero&#xff0c;将四大名著中的主要人物都插入这个表中&#xff0c;将实现过程中sql提交上上来 1、创建数据库db_ck mysql> create database db_ck; 2、创建表t_hero mysql> use db_ck Database changed mysql> create table …

svn删除所有隐藏.svn文件,文件夹脱离svn控制

新建一个文件&#xff0c;取名remove-svn-folders.reg&#xff0c;输入如下内容&#xff1a; Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\DeleteSVN] "Delete SVN Folders" [HKEY_LOCAL_MACHINE\SOFTWARE\Class…

文心一言:中国大模型时代的破局者与探路者

2023年&#xff0c;生成式人工智能&#xff08;AIGC&#xff09;的浪潮席卷全球&#xff0c;而百度推出的“文心一言”&#xff08;ERNIE Bot&#xff09;作为中国AI领域的代表性产品&#xff0c;迅速成为行业焦点。这款基于百度自主研发的“文心大模型”打造的对话式AI工具&am…

Ubuntu 安装docker docker-compose

Docker 通过提供轻量级、可移植且高效的解决方案&#xff0c;简化了软件开发和部署。“docker build”命令是 Docker 镜像创建过程的核心。本文将探讨 Docker 构建命令、用法以及 Docker 构建的优化。 Docker 构建有什么作用&#xff1f; Docker build 是一个命令行界面 CLI命…

Unity开发——CanvasGroup组件介绍和应用

CanvasGroup是Unity中用于控制UI的透明度、交互性和渲染顺序的组件。 一、常用属性的解释 1、alpha&#xff1a;控制UI的透明度 类型&#xff1a;float&#xff0c;0.0 ~1.0&#xff0c; 其中 0.0 完全透明&#xff0c;1.0 完全不透明。 通过调整alpha值可以实现UI的淡入淡…

每天五分钟深度学习PyTorch:向更深的卷积神经网络挑战的ResNet

本文重点 ResNet大名鼎鼎,它是由何恺明团队设计的,它获取了2015年ImageNet冠军,它很好的解决了当神经网络层数过多出现的难以训练的问题,它创造性的设计了跳跃连接的方式,使得卷积神经网络的层数出现了大幅度提升,设置可以达到上千层,可以说resnet对于网络模型的设计具…

大模型巅峰对决:DeepSeek vs GPT-4/Claude/PaLM-2 全面对比与核心差异揭秘

文章目录 一、架构设计深度解剖1.1 核心架构对比图谱1.2 动态MoE架构实现架构差异分析表 二、训练策略全面对比2.1 训练数据工程对比2.2 分布式训练代码对比DeepSeek混合并行实现GPT-4 Megatron实现对比 2.3 关键训练参数对比 三、性能表现多维评测3.1 基准测试全景对比3.2 推理…

基于hive的电信离线用户的行为分析系统

标题:基于hive的电信离线用户的行为分析系统 内容:1.摘要 随着电信行业的快速发展&#xff0c;用户行为数据呈现出海量、复杂的特点。为了深入了解用户行为模式&#xff0c;提升电信服务质量和精准营销能力&#xff0c;本研究旨在构建基于 Hive 的电信离线用户行为分析系统。通…

Python使用alembic实现数据库管理

python使用alembic实现数据库管理 环境准备 安装依赖&#xff1a; pip install sqlalchemy alembic项目结构 my_project/ ├── models.py # 定义数据模型 └── alembic/ # 迁移脚本目录&#xff08;自动生成&#xff09; 使用步骤&#xff1a; 1. 初始化Alembic环境 …

对WebSocket做一点简单的理解

1.概念 WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c; 并进行双向数据传输。 HTTP协议和WebSocket协议对比&#xff1a; HTTP是短连接 WebSocke…

kali虚拟机登录页面发癫 大写锁定输入不了密码

不知道怎么了 总是发癫 重启切换太麻烦了 还有时候不成功 kali其实可以开启虚拟键盘 如下 就解决的 发癫kali 发癫 发癫

基于Python的商品销量的数据分析及推荐系统

一、研究背景及意义 1.1 研究背景 随着电子商务的快速发展&#xff0c;商品销售数据呈现爆炸式增长。这些数据中蕴含着消费者行为、市场趋势、商品关联等有价值的信息。然而&#xff0c;传统的数据分析方法难以处理海量、多源的销售数据&#xff0c;无法满足现代电商的需求。…