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

news2025/3/14 20:39:07

背景介绍

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

目标效果

  • 两张图片堆叠放置,一张始终可见,另一张可调整可见范围。
  • 通过滑块拖动,控制上层图片的显示区域。
  • 适配 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.coloradmin.cn/o/2311307.html

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

相关文章

基于Arcgis的python脚本实现相邻矢量面的高度字段取平均值

文章目录 背景效果实现逻辑步骤1、准备数据2、python脚本3、执行通过脚本工具箱来执行背景 在地理信息系统(GIS)数据处理或三维建模等实际应用场景中,我们常常会遇到需要对矢量面数据进行精细化处理的需求。其中一个常见的任务便是对相邻的矢量面中的高度字段开展特定操作。…

Golang的网络流量控制

# Golang的网络流量控制 什么是网络流量控制&#xff1f; 网络流量控制是指针对网络数据传输过程中的流量进行管理和调控的一种技术手段。通过网络流量控制&#xff0c;我们可以对网络中的数据传输速率、带宽使用情况、数据包丢失率等进行监控和调整&#xff0c;以达到优化网络…

Python教程(一):基本语法、流程控制、数据容器

Python&#xff08;一&#xff09; 文章目录 Python&#xff08;一&#xff09;一、基础语法二、数据类型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.…

【AI深度学习基础】PyTorch初探

引言 PyTorch 是由 Facebook 开源的深度学习框架&#xff0c;专门针对 GPU 加速的深度神经网络编程&#xff0c;它的核心概念包括张量&#xff08;Tensor&#xff09;、计算图和自动求导机制。PyTorch作为Facebook开源的深度学习框架&#xff0c;凭借其动态计算图和直观的API设…

UE4 组件 (对话组件)

制作一个可以生成对话气泡&#xff0c;显示对话台词的简单组件。这个组件要的变量&#xff1a;台词&#xff08;外部传入&#xff09;。功能&#xff1a;开始对话&#xff08;生成气泡UI&#xff09; &#xff0c;结束对话。 一、对话组件创建 二、开始对话事件 1、注意这里获…

blender看不到导入的模型

参考&#xff1a;blender 快捷键 常见问题_blender材质预览快捷键-CSDN博客 方法一&#xff1a;视图-裁剪起点&#xff0c;设置一个很大的值 方法二&#xff1a;选中所有对象&#xff0c;对齐视图-视图对齐活动项-选择一个视图

【慕课网wiki项目学习笔记01】Spring Boot 项目搭建

2-2 新建SpringBoot项目 一、创建SpringBoot项目 &#xff08;1&#xff09;在SpringBoot官网创建 &#xff08;2.1&#xff09;在 IDEA 中创建 Group&#xff1a;公司名 Artifact&#xff1a;项目名 创建成功后开始下载Maven依赖&#xff08;选择右下角的Import Changes&…

【高分论文密码】AI大模型和R语言的全类型科研图形绘制,从画图、标注、改图、美化、组合、排序分解科研绘图每个步骤

在科研成果竞争日益激烈的当下&#xff0c;「一图胜千言」已成为高水平SCI期刊的硬性门槛——数据显示很多情况的拒稿与图表质量直接相关。科研人员普遍面临的工具效率低、设计规范缺失、多维数据呈现难等痛点&#xff0c;因此科研绘图已成为成果撰写中的至关重要的一个环节&am…

vue3-pc-template后台管理之角色管理与功能权限配置实践

在开发企业级应用时&#xff0c;权限控制无疑是至关重要且不可或缺的一部分。合理的权限控制不仅能够有效保障系统的安全性&#xff0c;还能确保不同用户角色在系统中拥有合适的操作权限&#xff0c;从而提高系统的使用效率和稳定性。本文将详细介绍如何在 Vue3 项目中实现功能…

Android Flow 示例

在Android开发的世界里&#xff0c;处理异步数据流一直是一个挑战。随着Kotlin的流行&#xff0c;Flow作为Kotlin协程库的一部分&#xff0c;为开发者提供了一种全新的方式来处理这些问题。今天&#xff0c;我将深入探讨Flow的设计理念&#xff0c;并通过具体的例子展示如何在实…

前端文件加载耗时过长解决方案

从你的 Network (网络) 面板 看到&#xff0c;许多 JS 文件的加载时间较长&#xff08;1~2秒&#xff09;&#xff0c;可能的原因如下&#xff1a; ✅ 可能的原因 1. 过多的 JS 请求&#xff08;多个小文件加载&#xff09; 你当前页面加载了很多小 JS 文件&#xff08;addSi…

Visual Studio 2022新建c语言项目的详细步骤

步骤1&#xff1a;点击创建新项目 步骤2&#xff1a;到了项目模板 --> 选择“控制台应用” (在window终端运行代码。默认打印"Hello World") --> 点击 “下一步” 步骤3&#xff1a;到了配置新项目模块 --> 输入“项目名称” --> 更改“位置”路径&…

物联网系统搭建

实验项目名称 构建物联网系统 实验目的 掌握物联网系统的一般构建方法。 实验要求&#xff1a; 1&#xff0e;构建物联网系统&#xff0c;实现前后端的交互。 实验内容&#xff1a; CS模式MQTT&#xff08;不带数据分析处理功能&#xff09; 实现智能设备与应用客户端的交…

PostgreSQL中的事务隔离

1. 事务隔离的概念 在数据库管理系统中&#xff0c;事务隔离是一项重要的功能&#xff0c;它能确保在并发访问数据库时事务之间能够独立运行&#xff0c;不会相互干扰。数据库系统通常支持不同级别的事务隔离&#xff0c;用来满足不同应用程序之间的需求。 2. 事务隔离的种类…

Android15请求动态申请存储权限完整示例

效果: 1.修改AndroidManifest.xml增加如下内容: <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-perm

unity学习62,尝试做第一个小游戏项目:flappy bird

目录 学习参考 1 创建1个unity 2D项目 1.1 2D项目模板选择 1.1.1 2D(built-in-Render pipeline) 1.1.2 universe 2D 1.1.3 这次选择 2D(built-in-Render pipeline) 1.2 创建项目 1.2.1 注意点 1.2.2 如果想修改项目名 2 导入美术资源包 2.1 下载一个flappy bird的…

【STM32F103ZET6——库函数】11.捕获红外信号

目录 红外原理 数据码 引导码 连发码 配置捕获引脚 使能引脚时钟 配置定时器 使能定时器时钟 配置输入捕获 中断优先级分组 配置定时器4中断 定时器中断使能 使能定时器 重写定时器中断服务函数 清空定时器中断标志位 例程 例程说明 main.h main.c HongWai…

unity调用本地部署deepseek全流程

unity调用本地部署deepseek全流程 deepseek本地部署 安装Ollama 搜索并打开Ollama官网[Ollama](https://ollama.com/download) 点击Download下载对应版本 下载后点击直接安装 安装deepseek大语言模型 官网选择Models 选择deepseek-r1&#xff0c;选择对应的模型&#xff0…

AI绘画软件Stable Diffusion详解教程(6):文生图、提示词细说与绘图案例

文生图即以文字描述来生成图像&#xff0c;这是目前所有AI绘画软件的基本功能之一。要想画一副好的图片&#xff0c;除了选择好的模型&#xff0c;在文生图中&#xff0c;提示词特别关键。 一、什么是提示词&#xff08;Prompt&#xff09; 提示词又称创意、关键词、咒语、ca…

SAP监控体系和机制

SAP监控体系 SAP监控体系是一个多层次、多维度的综合系统&#xff0c;旨在确保SAP系统的性能、可用性、安全性和稳定性。以下是SAP监控体系的主要组成部分&#xff1a; 1. 技术监控&#xff08;Technical Monitoring&#xff09; 目标&#xff1a;监控SAP系统的基础设施和技术…