API-案例-放大镜效果

学习目标:

  • 掌握案例-放大镜效果

学习内容:

  1. 业务分析
  2. 思路分析
  3. 放大镜完整代码

业务分析:

  • 鼠标经过对应小盒子,左侧中等盒子显示对应中等图片;
  • 鼠标经过中盒子,右侧会显示放大镜效果的大盒子;
  • 黑色遮罩盒子跟着鼠标来移动;
  • 鼠标在中等盒子上移动,大盒子的图片跟着显示对应位置。

思路分析:

  • 鼠标经过小盒子,左侧中等盒子显示对应中等图片:
  1. 获取对应的元素。

  2. 采取事件委托的形式,监听鼠标经过小盒子里面的图片, 注意此时需要使用 mouseover 事件,因为需要事件冒泡触发small

  3. 让鼠标经过小图片的爸爸li盒子,添加类,其余的li移除类(注意先移除,后添加)。

  4. 鼠标经过小图片,可以拿到小图片的src, 可以做两件事:

    让中等盒子的图片换成这个 这个小图片的src
    让大盒子的背景图片,也换成这个小图片的 src (稍后做)
    
//获取三个盒子//2.小盒子 图片切换效果const small = document.querySelector('.small')//中盒子const middle = document.querySelector('.middle')//大盒子const large = document.querySelector('.large')//2.事件委托small.addEventListener('mouseover', function (e) {if (e.target.tagName === 'IMG') {// console.log(11)//排他  干掉以前的active li  上面this.querySelector('.active').classList.remove('active')//当前元素的爸爸添加activee.target.parentNode.classList.add('active')//拿到当前小图片的src// console.log(e.target.src)//让中盒子里面的图片 ,src更换为  小图片srcmiddle.querySelector('img').src = e.target.src//大盒子更换背景图片large.style.backgroundImage = `url(${e.target.src})`}})
  • 鼠标经过中等盒子,右侧大盒子显示:
  1. 用到鼠标经过和离开,鼠标经过中盒子,大盒子 利用 display 来显示和隐藏。
  2. 鼠标离开不会立马消失,而是有200ms的延时,用户体验更好,所以尽量使用定时器做个延时 setTimeout
  3. 显示和隐藏也尽量定义一个函数,因为鼠标经过离开中等盒子,会显示隐藏,同时,鼠标经过大盒子,也会显示和隐藏。
  4. 给大盒子里面的背景图片一个默认的第一张图片。
 //3.鼠标经过中等盒子,显示隐藏  大盒子middle.addEventListener('mouseenter', show)middle.addEventListener('mouseleave', hide)let timeId = null//显示函数  显示大盒子function show() {//先清除定时器clearTimeout(timeId)large.style.display = 'block'}//隐藏函数  隐藏大盒子function hide() {timeId = setTimeout(function () {large.style.display = 'none'}, 200)}
  • 黑色遮罩盒子跟着鼠标来移动:
  1. 先做鼠标经过中等盒子,显示隐藏黑色遮罩的盒子。
  2. 让黑色遮罩跟着鼠标来走, 需要用到鼠标移动事件 mousemove
  3. 让黑色盒子的移动的核心思想:不断把鼠标在中等盒子内的坐标给黑色遮罩层 let top 值,这样遮罩层就可以跟着移动了。

需求
我们要的是鼠标在中等盒子内的坐标, 没有办法直接得到。
得到1: 鼠标在页面中的坐标。
得到2: 中等盒子在页面中的坐标

算法
得到鼠标在页面中的坐标 利用事件对象的 pageX
得到middle中等盒子在页面中的坐标 middle.getBoundingClientRect()
鼠标在middle 盒子里面的坐标 = 鼠标在页面中的坐标 - middle 中等盒子的坐标。
黑色遮罩层不断得到 鼠标在middle 盒子中的坐标 就可以移动起来了。

注意 y坐标特殊,需要减去 页面被卷去的头部
为什么不用 box.offsetLet 和 box.offsetTop 因为这俩属性跟带有定位的父级有关系,很容被父级影响,而getBoundingClientRect() 不受定位的父元素的影响

限定遮罩的盒子只能在middle 内部移动,需要添加判断:
限定水平方向 大于等于0 并且小于等于 400。
限定垂直方向 大于等于0 并且小于等于 400。

遮罩盒子移动的坐标
声明一个 mx 作为移动的距离。
水平坐标 x 如果 小于等于100 ,则移动的距离 mx 就是 0 不应该移动
水平坐标 如果 大于等于100 并且小于300,移动的距离就是 mx - 100 (100是遮罩盒子自身宽度的一半)
水平坐标 如果 大于等于300,移动的距离就是 mx 就是200 不应该在移动了
其实我们发现水平移动, 就在 100 ~ 200 之间移动的。
垂直同理。

let mx = 0, my = 0;
if (x <= 100) mx = 0
if (x > 100 && x < 300) mx = x - 100
if (x >= 300) mx = 200if (y <= 100) my = 0
if (y > 100 && y < 300) my = y - 100
if (y >= 300) my = 200

大盒子图片移动的计算方法
中等盒子是 400px 大盒子 是 800px 的图片。
中等盒子移动1px, 大盒子就应该移动2px, 只不过是负值。

large.style.backgroundPositionX = - 2 * mx + 'px'
large.style.backgroundPositionY = - 2 * my + 'px'
//4.鼠标经过大盒子,显示隐藏 大盒子large.addEventListener('mouseenter', show)large.addEventListener('mouseleave', hide)//5.鼠标经过中等盒子,显示隐藏 黑色遮罩层const layer = document.querySelector('.layer')middle.addEventListener('mouseenter', function () {layer.style.display = 'block'})middle.addEventListener('mouseleave', function () {layer.style.display = 'none'})//6.移动盒子遮罩盒子middle.addEventListener('mousemove', function (e) {// let x = 20, y = 20// console.log(11)//鼠标在middle盒子里面的坐标 = 鼠标在页面中的坐标 - middle中等盒子的坐标// console.log(e.pageX)鼠标在页面中的坐标//middle 中等盒子的坐标// console.log(middle.getBoundingClientRect().left)let x = e.pageX - middle.getBoundingClientRect().leftlet y = e.pageY - middle.getBoundingClientRect().top - document.documentElement.scrollTop// console.log(x, y)//黑色遮罩移动 在middle盒子内  限定移动的距离if (x >= 0 && x <= 400 && y >= 0 && y <= 400) {//黑色盒子不是一直移动的//声明2个变量  黑色盒子移动的 mx my变量let mx = 0, my = 0if (x < 100) mx = 0if (x >= 100 && x <= 300) mx = x - 100if (x > 300) mx = 200if (y < 100) my = 0if (y >= 100 && y <= 300) my = y - 100if (y > 300) my = 200layer.style.left = mx + 'px'layer.style.top = my + 'px'//大盒子的背景图片要跟随 中等盒子移动  存在的关系是2倍large.style.backgroundPositionX = -2 * mx + 'px'large.style.backgroundPositionY = -2 * my + 'px'}

放大镜完整代码:

<script>//获取三个盒子//2.小盒子 图片切换效果const small = document.querySelector('.small')//中盒子const middle = document.querySelector('.middle')//大盒子const large = document.querySelector('.large')//2.事件委托small.addEventListener('mouseover', function (e) {if (e.target.tagName === 'IMG') {// console.log(11)//排他  干掉以前的active li  上面this.querySelector('.active').classList.remove('active')//当前元素的爸爸添加activee.target.parentNode.classList.add('active')//拿到当前小图片的src// console.log(e.target.src)//让中盒子里面的图片 ,src更换为  小图片srcmiddle.querySelector('img').src = e.target.src//大盒子更换背景图片large.style.backgroundImage = `url(${e.target.src})`}})//3.鼠标经过中等盒子,显示隐藏  大盒子middle.addEventListener('mouseenter', show)middle.addEventListener('mouseleave', hide)let timeId = null//显示函数  显示大盒子function show() {//先清除定时器clearTimeout(timeId)large.style.display = 'block'}//隐藏函数  隐藏大盒子function hide() {timeId = setTimeout(function () {large.style.display = 'none'}, 200)}//4.鼠标经过大盒子,显示隐藏 大盒子large.addEventListener('mouseenter', show)large.addEventListener('mouseleave', hide)//5.鼠标经过中等盒子,显示隐藏 黑色遮罩层const layer = document.querySelector('.layer')middle.addEventListener('mouseenter', function () {layer.style.display = 'block'})middle.addEventListener('mouseleave', function () {layer.style.display = 'none'})//6.移动盒子遮罩盒子middle.addEventListener('mousemove', function (e) {// let x = 20, y = 20// console.log(11)//鼠标在middle盒子里面的坐标 = 鼠标在页面中的坐标 - middle中等盒子的坐标// console.log(e.pageX)鼠标在页面中的坐标//middle 中等盒子的坐标// console.log(middle.getBoundingClientRect().left)let x = e.pageX - middle.getBoundingClientRect().leftlet y = e.pageY - middle.getBoundingClientRect().top - document.documentElement.scrollTop// console.log(x, y)//黑色遮罩移动 在middle盒子内  限定移动的距离if (x >= 0 && x <= 400 && y >= 0 && y <= 400) {//黑色盒子不是一直移动的//声明2个变量  黑色盒子移动的 mx my变量let mx = 0, my = 0if (x < 100) mx = 0if (x >= 100 && x <= 300) mx = x - 100if (x > 300) mx = 200if (y < 100) my = 0if (y >= 100 && y <= 300) my = y - 100if (y > 300) my = 200layer.style.left = mx + 'px'layer.style.top = my + 'px'//大盒子的背景图片要跟随 中等盒子移动  存在的关系是2倍large.style.backgroundPositionX = -2 * mx + 'px'large.style.backgroundPositionY = -2 * my + 'px'}})</script>

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

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

相关文章

智能物联网鱼缸

硬件部分及接线图 工具 继电器、开发板、物联网os、云平台 微信小程序 结构&#xff1a;images、pages两个为主体。 标题头部分 <view class"container"> <view class"head_box"> <image src"/images/面性鱼缸.png"><…

【C++】 解决 C++ 语言报错:Invalid Use of Incomplete Type

文章目录 引言 在 C 编程中&#xff0c;“Invalid Use of Incomplete Type” 是一种常见错误。此错误通常在程序试图使用未完全定义的类或结构时发生。这种错误不仅会导致编译失败&#xff0c;还可能导致程序行为不可预测。本文将详细探讨无效使用不完整类型的成因、检测方法及…

【图论算法题记录】岛屿问题汇总

岛屿数量 题目&#x1f517; 题目描述 给定一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的矩阵&#xff0c;你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成&#xff0c;并且四周都是水域。你可以假设矩阵外均被水包围。 …

【已解决】CentOS8安装lrzsz报错:Error: Failed to download metadata for repo ‘BaseOS‘

这里写自定义目录标题 系统信息安装lrzsz解决方案开始使用 系统信息 #cat /etc/redhat-release CentOS Linux release 8.1.1911 (Core) 安装lrzsz # yum install lrzsz CentOS-8 - AppStream …

【Threejs进阶教程-优化篇】4.Vue/React与threejs如何解决冲突和卡顿(续)

Vue/React与threejs如何解决冲突和卡顿-续 使用说明核心思路环境搭建(vuethree)vue运行机制分析业务分离使用threejs做背景 3D模块封装使用ES6的Class来让逻辑性更强Threejs尽量按需引入创建一个类扩展写法本次代码执行顺序 扩展内容添加orbitControls和辅助线解决事件覆盖 与V…

C++模板元编程(三)——类型萃取

类型萃取(type_traits)是一种编译时技术&#xff0c;用于在编译期间获取和操作类型的信息&#xff0c;主要用于泛型编程以及在编译时做出决策。 文章目录 常见的类型萃取内部实现std::is_integral\<T\>std::enable_if_t<_Test, T> 应用 常见的类型萃取 在C11的<…

Java请求webService,IDEA生成客户端调用代码

Axis是Apache开放源代码组织的一个项目&#xff0c;全称为Apache Extensible Interaction System&#xff0c;简称Axis。它是一个基于Java的SOAP&#xff08;Simple Object Access Protocol&#xff0c;简单对象访问协议&#xff09;引擎&#xff0c;提供创建服务器端、客户端和…

游戏开发面试题3

unity如何判断子弹射击到敌人&#xff0c;如果子弹特别快怎么办 使用物理学碰撞检测。使用Unity的物理组件&#xff0c;如Rigidbody和Collider&#xff0c;将子弹和敌人都设置为有一定的物理碰撞属性&#xff0c;当子弹碰到敌人的时候&#xff0c;就会触发OnCollisionEnter()事…

游戏开发面试题2

详细说下堆排序。 堆排序是一种选择排序算法&#xff0c;它的基本思想是&#xff1a;将待排序序列构造成一个大顶堆&#xff0c;此时&#xff0c;整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换&#xff0c;此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个…

作业训练二编程题6. 小A的计算器

【问题描述】 以往的操作系统内部的数据表示都是二进制方式&#xff0c;小A新写了一个操作系统&#xff0c;系统内部的数据表示为26进制&#xff0c;其中0-25分别由a-z表示。 现在小A要在这个操作系统上实现一个计算器&#xff0c;这个计算器要能实现26进制数的加法运算…

Ajax与Fetch API在Web开发中的性能、用法与未来趋势比较

Ajax和Fetch都是JavaScript中用于从客户端向服务器发送请求以获取数据的技术&#xff0c;但它们之间存在一些显著的区别。以下是对这两种技术的详细比较&#xff1a; 一、技术基础与实现方式 Ajax&#xff1a; 基础&#xff1a;Ajax全称为Asynchronous JavaScript and XML&…

LabVIEW的Actor Framework (AF) 结构介绍

LabVIEW的Actor Framework (AF) 是一种高级架构&#xff0c;用于开发并发、可扩展和模块化的应用程序。通过面向对象编程&#xff08;OOP&#xff09;和消息传递机制&#xff0c;AF结构实现了高效的任务管理和数据处理。其主要特点包括并发执行、动态可扩展性和强大的错误处理能…

ROS——多个海龟追踪一个海龟实验

目标 通过键盘控制一个海龟&#xff08;领航龟&#xff09;的移动&#xff0c;其余生成的海龟通过监听实现追踪定期获取领航龟和其余龟的坐标信息&#xff0c;通过广播告知其余龟&#xff0c;进行相应移动其余龟负责监听 疑惑点&#xff08;已解决&#xff09; int main(int…

k8s 部署RuoYi-Vue-Plus之redis搭建

1.直接部署一个pod 需要挂载存储款, 可参考 之前文章设置 https://blog.csdn.net/weimeibuqieryu/article/details/140183843 2.部署yaml 先创建命名空间ruoyi, 有就不用创建了 kubectl create namespace ruoyi创建部署文件 redis-deploy.yaml kind: PersistentVolume api…

程序员学长 | 快速学会一个算法,xLSTM

本文来源公众号“程序员学长”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;快速学会一个算法&#xff0c;xLSTM 今天给大家分享一个超强的算法模型&#xff0c;xLSTM。 xLSTM&#xff08;Extended Long Short-Term Memory&…

Spring Boot的无缝衔接:深入解析与实践

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ &#x1f680;The begin&#x1f697;点点关注&#xff0c;收藏不迷路&#x1f6a9; 引言 在快速迭代的软件开发环境中&#xff0c;无缝衔接是提升开发效率、降低维护成本、增强系统稳定性的关键。Spring Boo…

Electron开发 - 如何在主进程Main中让node-fetch使用系统代理

背景 开发过程中&#xff0c;用户设置的系统代理是不同的&#xff0c;比如公司内的服务器&#xff0c;所以就要动态地使用系统代理来访问&#xff0c;但是主进程默认为控制台级别的请求&#xff0c;不走系统代理&#xff0c;除非你指定系统代理配置&#xff0c;这个就就有了这…

轻松上手MYSQL:MYSQL事务隔离级别的奇幻之旅

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》《MYSQL》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 ✨欢迎加入探索MYSQL索引数据结构之旅✨ &#x1f44b; 大家好&#xff01;文本学习…

【话题】IT专业入门,高考假期预习指南

IT专业入门&#xff0c;高考假期预习指南 亲爱的高考学子们&#xff0c; 七月的阳光&#xff0c;如同你们的梦想&#xff0c;炽热而明亮。当你们手中的笔落下最后一道题的答案&#xff0c;那不仅仅是对过去十二年寒窗苦读的告别&#xff0c;更是对未知世界探索的启程号角。你们…

ExtruOnt——为工业 4.0 系统描述制造机械类型的本体

概述 论文地址 &#xff1a;https://arxiv.org/abs/2401.11848 原文地址&#xff1a;https://ai-scholar.tech/articles/ontology/ExtruOnt 在工业 4.0 应用场景中&#xff0c;以机器可解释代码提供的、语义丰富的制造机械描述可以得到有效利用。然而&#xff0c;目前显然还缺…