当前位置: 首页 > news >正文

图片放大镜案例

案例:图片放大镜

该案例实现了一个“图片放大镜”功能:鼠标悬停在小图上时,会显示一个跟随鼠标的灰色选区框,同时右侧显示选区对应的放大区域;鼠标离开时,选区框和放大区域自动隐藏。

相应的效果:
在这里插入图片描述

一、HTML结构搭建:确定核心元素

首先需要定义三个核心元素,分别承担“小图容器”“选区框”“放大区域”的角色:

<!-- 小图容器:放置原图,作为鼠标交互的主区域 -->
<div class="middle"><!-- 选区框 --><div class="lawer"></div>
</div>
<!-- 放大区域:显示选区对应的放大效果(初始隐藏) -->
<div class="large" style="display: none;"></div>
  • .middle:小图容器,背景为需要放大的原图(尺寸200x200px)。
  • .lawer:灰色半透明选区框(尺寸80x80px),用于标记当前需要放大的局部区域。
  • .large:放大区域,背景为同一张原图(但尺寸放大到400x400px),通过背景定位显示选区对应的局部。
二、CSS样式设置:控制元素布局与外观

通过CSS设置元素的尺寸、定位方式和初始状态,为交互效果奠定基础:

/* 小图容器:相对定位(作为选区框的父级参照物) */
.middle {position: relative;width: 200px;height: 200px;background: url(./images/2.png) no-repeat; /* 小图背景 */background-size: 200px 200px; /* 原图尺寸 */
}/* 选区框:绝对定位(相对于小图容器) */
.lawer {position: absolute;top: 0;left: 0;width: 80px;height: 80px;background-color: gray;opacity: 0.7; /* 半透明,不遮挡原图 */display: none; /* 初始隐藏 */
}/* 放大区域:绝对定位(在小图右侧) */
.large {position: absolute;top: 0;left: 250px;width: 400px;height: 400px; /* 尺寸是小图的2倍(放大倍数为2) */background: url(./images/2.png) no-repeat;background-size: 400px 400px; /* 原图放大2倍显示 */
}
  • 放大逻辑:.large的尺寸是.middle的2倍
三、JavaScript交互逻辑:实现动态效果
1. 元素获取与变量初始化

首先获取DOM元素并定义定时器变量(用于控制延迟隐藏):

const middle = document.querySelector('.middle'); // 小图容器
const large = document.querySelector('.large'); // 放大区域
const lawer = document.querySelector('.lawer'); // 选区框
let timeId; // 定时器ID,用于清除延迟隐藏
2. 显示/隐藏控制:鼠标进入/离开时的状态切换

当鼠标进入小图或放大区域时,显示选区框和放大区域;离开时延迟隐藏(避免快速切换时闪烁):

// 显示放大区域和选区框
function appear() {clearTimeout(timeId); // 清除延迟隐藏定时器(防止误隐藏)large.style.display = 'block'; // 显示放大区域
}// 延迟隐藏放大区域(100ms延迟)
function disappear() {timeId = setTimeout(() => {large.style.display = 'none'; // 100ms后隐藏}, 100);
}// 显示选区框
function lawerAppear() {lawer.style.display = 'block';
}// 隐藏选区框
function lawerDisappear() {lawer.style.display = 'none';
}// 鼠标进入小图时,显示元素
middle.addEventListener('mouseenter', appear);
middle.addEventListener('mouseenter', lawerAppear);// 鼠标离开小图时,延迟隐藏
middle.addEventListener('mouseleave', disappear);
middle.addEventListener('mouseleave', lawerDisappear);// 鼠标进入放大区域时,保持显示(避免移出小图但在放大区域时隐藏)
large.addEventListener('mouseenter', appear);
large.addEventListener('mouseleave', disappear);
3. 计算鼠标在小图内的相对位置

当鼠标在小图上移动时,计算鼠标相对于小图的坐标,控制选区框在小图内移动

middle.addEventListener('mousemove', (e) => {// 计算鼠标在小图内的相对X坐标  const x = e.pageX - middle.getBoundingClientRect().left;// 计算鼠标在小图内的相对Y坐标(减去页面滚动距离)const y = e.pageY - middle.getBoundingClientRect().top - document.documentElement.scrollTop;// 获取小图和选区框的尺寸const middleW = parseInt(getComputedStyle(middle).width); // 小图宽度const middleH = parseInt(getComputedStyle(middle).height); // 小图高度const lawerW = parseInt(getComputedStyle(lawer).width); // 选区框宽度const lawerH = parseInt(getComputedStyle(lawer).height); // 选区框高度// 限制选区框在小图内(边界处理)let mx = 0, my = 0;//使得鼠标在一定区域时,展示的大图内容相同if (x < lawerW / 2) {mx = 0; } else if (x > middleW - lawerW / 2) {mx = middleW - lawerW; } else {mx = middleW - lawerW / 2;}// 同上if (y < lawerH / 2) {my = 0; } else if (y > middleH - lawerH / 2) {my = middleH - lawerH;} else {my = middleH - lawerH / 2; }// 设置选区框位置lawer.style.left = mx + 'px';lawer.style.top = my + 'px';
});
4. 放大区域同步:根据选区位置调整背景定位

放大区域的背景图需要与选区框位置同步,由于放大倍数为2倍,背景定位需反向偏移2倍的选区位置:

// 接上面的mousemove事件:同步放大区域的背景位置
large.style.backgroundPositionX = -2 * mx + 'px'; // X轴反向偏移2倍
large.style.backgroundPositionY = -2 * my + 'px'; // Y轴反向偏移2倍
四、问题
  1. 定时器id总是没有及时清除,导致在移入移出使的效果展示很差。
  2. 大图是二倍图,放大区域的偏移量要为鼠标移动逻辑值二倍,且大盒子中的背景图移动是相反的,调整背景图显示的坐标原点。
完整代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>body {padding: 0;margin: 0;}div {width: 200px;height: 200px;background-color: pink;margin-bottom: 500px;}.middle {position: relative;/* height: 100%; */background: url(./images/2.png) no-repeat;/* 缩放 */background-size: 200px 200px;}.large {position: absolute;top: 0;left: 250px;background-color: blue;background: url(./images/2.png) no-repeat;background-size: 400px 400px;}.lawer {position: absolute;top: 0;left: 0;width: 80px;height: 80px;background-color: gray;opacity: .7;}body {height: 2000px;}</style>
</head><body><div class="middle"><div class="lawer"></div></div><div class="large" style="display: none;"></div><script>const middle = document.querySelector('.middle');const large = document.querySelector('.large');const lawer = document.querySelector('.middle .lawer');let timeId;function disappear() {// 还是定时器的问题,有开有关!timeId = setTimeout(function () {large.style.display = 'none';}, 100)}function appear() {clearInterval(timeId);large.style.display = 'block';}function lawerapper() {lawer.style.display = 'block';}function lawerdisapper() {lawer.style.display = 'none';}middle.addEventListener('mouseenter', appear);middle.addEventListener('mouseleave', disappear);large.addEventListener('mouseenter', appear);large.addEventListener('mouseleave', disappear);middle.addEventListener('mouseenter', lawerapper);middle.addEventListener('mouseleave', lawerdisapper);middle.addEventListener('mousemove', function (e) {let x = e.pageX - middle.getBoundingClientRect().left;// 多减去被卷曲的距离let y = e.pageY - middle.getBoundingClientRect().top - document.documentElement.scrollTop;// 提取出元素的宽和高// 先获得带单位的数据之后提取出来进行计算middleW = parseInt(getComputedStyle(middle).width);middleH = parseInt(getComputedStyle(middle).height);lawerW = parseInt(getComputedStyle(lawer).width)lawerH = parseInt(getComputedStyle(lawer).height);if (x >= 0 && x <= middleW && y >= 0 && y <= middleH) {let mx = 0, my = 0;if (x < lawerW / 2) {mx = 0;} else if (x >= lawerW / 2 && x <= middleW - lawerW / 2) {mx = x - lawerW / 2;} else {mx = middleW - lawerW;}if (y < lawerH / 2) {my = 0;} else if (y >= lawerH / 2 && y <= middleH - lawerH / 2) {my = y - lawerH / 2;} else {my = middleH - lawerH;}lawer.style.left = mx + 'px';lawer.style.top = my + 'px';large.style.backgroundPositionX = -2 * mx + 'px';large.style.backgroundPositionY = -2 * my + 'px';}})</script>
</body></html>
http://www.xdnf.cn/news/1153117.html

相关文章:

  • Patch-wise Structural:一种引入局部统计特性的时序预测损失函数
  • CS231n-2017 Lecture3线性分类器、最优化笔记
  • QT窗口(7)-QColorDiag
  • [spring6: AspectJAdvisorFactory AspectJProxyFactory]-源码解析
  • Linux C 信号操作
  • “外卖大战”正在改变国内“大零售”
  • 图解系统-小林coding笔记
  • 骑行邂逅LV巨轮,VELO维乐Angel Rise坐垫与时尚超适配
  • YOLOv11改进 | RFAConv重塑空间注意力助力性能提升
  • 开关电源和线性电源Multisim电路仿真实验汇总——硬件工程师笔记
  • 使用UV管理FastAPI项目
  • HOT100——动态规划篇Leetcode221. 最大正方形
  • 模型自信度提升:增强输出技巧
  • 纸板制造糊机操作
  • Datawhale AI数据分析 作业
  • 基于朴素贝叶斯的姓名性别预测系统
  • Ubuntu20.04 samba配置
  • 2023年CSP入门级第二轮第四题——旅游巴士
  • 马走日题解
  • Apache Kafka 学习笔记
  • 手撕Spring底层系列之:注解驱动的魔力与实现内幕
  • Node.js dns 模块深入解析
  • Vite的优缺点(精简版)
  • leetcode_53 最大子数组和
  • 学习 Python 爬虫需要哪些基础知识?
  • KVM中使用桥接模式.运维就业技术教程
  • Linux操作系统之线程(三)
  • 定时器与间歇函数
  • STC增强型单片机寄存器 PWM EEPROM TMOD TCON
  • 在摄像机视图中想像在普通 3D 视口里那样随意移动