【JS案例】JS实现图片放大镜功能

JS案例·图片放大镜

🌟效果展示 

🌟HTML结构

🌟CSS样式

🌟实现思路  

🌟具体实现 

1.初始化数据图片

 2.获取所需DOM元素

 3.初始化页面

初始化缩略图

绑定事件

🌟完整代码

🌟写在最后 


🌟效果展示 


🌟HTML结构

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="./index.css">
</head>
<body>
  <!--最外层容器 -->
  <div class="container">
    <!-- 左侧原图 -->
    <div class="left-img">
      <!-- 遮罩层 -->
      <div class="mask"></div>
    </div>
    <!-- 右侧放大图片 -->
    <div class="right-img"></div>
    <!-- 缩略图集合 -->
    <div class="img-list-wrapper">
      <ul class="img-list">
        <li></li>
      </ul>
    </div>
  </div>
  <script src="./index.js"></script>
</body>
</html>

🌟CSS样式

* {
  margin: 0;
  padding: 0;
  list-style: none;
}

.container {
  width: 1000px;
  height: 600px;
  margin: 50px auto;
  font-size: 0;
}

.left-img {
  width: 490px;
  height: 510px;
  margin-right: 16px;
  border: 1px solid #eee;
  display: inline-block;
  /* 图片 */
  background-image: url(./images/imgA_2.jpg);
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
  /* 遮罩层相对我进行定位 */
  position: relative;
}
.mask {
  width: 230px;
  height: 230px;
  background-image: url(./images/bg.png);
  position: absolute;
  top: 0;
  left: 0;
  /* opacity: 0; */
}
.right-img {
  width: 490px;
  height: 510px;
  border: 1px solid #eee;
  display: inline-block;
  background-image: url(./images/imgA_3.jpg);
  background-repeat: no-repeat;
  /* opacity: 0; */
}

.img-list-wrapper {
  width: 490px;
  text-align: center;
  margin-top: 10px;
}
.img-list {
  display: inline-block;
}
.img-list li {
  display: inline-block;
  width: 60px;
  height: 60px;
  margin: 0 5px;
  cursor: pointer;
  background-image: url(./images/imgA_1.jpg);
  background-repeat: no-repeat;
  border: 2px solid #000;
  /* border: 1px solid #eee; */
}

🌟实现思路  

在敲完上面HTML文件和CSS文件后可以看到下图效果(图片素材及完整代码文末可下载):

可以看到整体分为四块:

1. 阴影区域:其实是一张很小的像素图铺满元素形成,后续跟随鼠标移动,所选区域在右侧高清展示。

2.图片大图:就是展示的图片。

3.缩略图列表:点击切换图片。

4.高清大图展示区域。

在项目中②和③一般可以用同一种图,④会使用一张高清图。我们这里是使用三张图片来开发,缩略图,普通展示图,高清图。

因为①和④是鼠标移入才出现,所以这里 给.mask.right-img加上opacity: 0;属性如下:

接下来我们需要做的就是在鼠标移入和移出时在右侧展示与隐藏高清图,从而实现图片放大镜效果。


🌟具体实现 

1.初始化数据图片

 这里用的就是本地图片,所以先初始化数据图片,三种大小对应缩略图,展示图,高清图:

// 初始化数据图片
var imgs = {
  // 小图
  small: ['imgA_1.jpg', 'imgB_1.jpg', 'imgC_1.jpg'],
  // 中图
  middle: ['imgA_2.jpg', 'imgB_2.jpg', 'imgC_2.jpg'],
  // 大图
  large: ['imgA_3.jpg', 'imgB_3.jpg', 'imgC_3.jpg']
}

 2.获取所需DOM元素

 因为需要频繁操作DOM元素,这里简单封装一个获取DOM元素方法:

// 单一元素
function $(selector) {
  return document.querySelector(selector);
}

// 多个元素
function $$(selector) {
  return document.querySelectorAll(selector);
}

接下来获取需要用到的元素:

 3.初始化页面

初始化缩略图

初始化所有缩略图,及③区域的缩略图列表。拿到缩略图值拼接字符串,将<li></li>插入页面,并默认选中第一张缩略图:

// 初始化所有缩略图
 let str = '';
 for(var i=0; i<imgs.small.length; i++) {
   str += '<li style="background-image: url(./images/'+ imgs.small[i] +');"></li>'
 }
 smallImg.innerHTML = str
// 默认选中第一个缩略图
$('.img-list li').style.border = '2px solid #000';

绑定事件

该效果中一共有两种事件,一个是点击缩略图,另一个是鼠标移入移出。

点击缩略图切换展示图片

smallImg.onclick = function (e) {
  // 判断我点击的元素是li元素
  if (e.target.tagName == 'LI') {
    // 让所有li元素取消border
    let lis = $$('li');
    for (let i = 0; i < lis.length; i++) {
      lis[i].style.border = 'none';
    }
    // 让选中的li元素添加border
    e.target.style.border = '2px solid #000';

    // 点击缩略图后,原图和大图也需要跟着变换,
    // 点的是第几个元素, 获取元素索引
    // [1,2,3].indexOf(3) == 2
    let index = [].indexOf.call(lis, e.target);
    midImg.style.backgroundImage = 'url(./images/' + imgs.middle[index] + ')';
    largeImg.style.backgroundImage = 'url(./images/' + imgs.large[index] + ')';
  }
}

移入移出事件

这里需要计算遮罩层离边框的距离,可得到的距离有:

绿色:边框距离浏览器左边的距离

红色:鼠标距离浏览器左边的距离

黄色:遮罩层一半的距离

通过这几个值就可求出遮罩层距离边框的距离left了,同理top值一样的求法

鼠标移入

midImg.onmousemove = function (e) {
    // 让遮罩层和大图展示
    mask.style.opacity = 1;
    largeImg.style.opacity = 1;

    // 根据鼠标位置计算遮罩层的位置
    let left = e.clientX - midImg.offsetLeft - mask.offsetWidth / 2;
    // 同理
    let top = e.clientY - midImg.offsetTop - mask.offsetHeight / 2;

    // 边界条件
    if (left <= 0) {
      left = 0;
    }
    if (top <= 0) {
      top = 0;
    }
    if (left >= midImg.offsetWidth - mask.offsetWidth) {
      left = midImg.offsetWidth - mask.offsetWidth
    }
    if (top >= midImg.offsetHeight - mask.offsetHeight) {
      top = midImg.offsetHeight - mask.offsetHeight
    }
    // 根据top和left调整mask的位置
    mask.style.left = left + 'px';
    mask.style.top = top + 'px';

    // 根据top 和 left,修改大图的位置,background-position-x
    largeImg.style.backgroundPositionX = -left + 'px';
    largeImg.style.backgroundPositionY = -top + 'px';

  }

鼠标移出

  midImg.onmouseleave = function (e) {
    // 让遮罩层和大图消失
    mask.style.opacity = 0;
    largeImg.style.opacity = 0;
  }

🌟完整代码

最后在把js代码进行整理与二次封装,完整代码如下:

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="./index.css">
</head>
<body>
  <!--最外层容器 -->
  <div class="container">
    <!-- 左侧原图 -->
    <div class="left-img">
      <!-- 遮罩层 -->
      <div class="mask"></div>
    </div>
    <!-- 右侧放大图片 -->
    <div class="right-img"></div>
    <!-- 缩略图集合 -->
    <div class="img-list-wrapper">
      <ul class="img-list">
      </ul>
    </div>
  </div>
  <script src="./index.js"></script>
</body>
</html>

index.css

* {
  margin: 0;
  padding: 0;
  list-style: none;
}

.container {
  width: 1000px;
  height: 600px;
  margin: 50px auto;
  font-size: 0;
}

.left-img {
  width: 490px;
  height: 510px;
  margin-right: 16px;
  border: 1px solid #eee;
  display: inline-block;
  /* 图片 */
  background-image: url(./images/imgA_2.jpg);
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
  /* 遮罩层相对我进行定位 */
  position: relative;
}
.mask {
  width: 230px;
  height: 230px;
  background-image: url(./images/bg.png);
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0;
}
.right-img {
  width: 490px;
  height: 510px;
  border: 1px solid #eee;
  display: inline-block;
  background-image: url(./images/imgA_3.jpg);
  background-repeat: no-repeat;
  opacity: 0;
}

.img-list-wrapper {
  width: 490px;
  text-align: center;
  margin-top: 10px;
}
.img-list {
  display: inline-block;
}
.img-list li {
  display: inline-block;
  width: 60px;
  height: 60px;
  margin: 0 5px;
  cursor: pointer;
  background-image: url(./images/imgA_1.jpg);
  background-repeat: no-repeat;
  /* border: 2px solid #000; */
  border: 1px solid #eee;
}

index.js

// 封装一个获取DOM元素的方法

// 单一元素
function $(selector) {
  return document.querySelector(selector);
}

// 多个元素
function $$(selector) {
  return document.querySelectorAll(selector);
}

// 初始化数据图片
let imgs = {
  // 小图
  small: ['imgA_1.jpg', 'imgB_1.jpg', 'imgC_1.jpg'],
  // 中图
  middle: ['imgA_2.jpg', 'imgB_2.jpg', 'imgC_2.jpg'],
  // 大图
  large: ['imgA_3.jpg', 'imgB_3.jpg', 'imgC_3.jpg']
}

// 获取一些将要使用的dom元素
let container = $('.container');
let largeImg = $('.right-img');
let midImg = $('.left-img');
let smallImg = $('.img-list');
let mask = $('.mask');

// 两大类事件类型, 点击, 鼠标移入移出
// 1. 点击事件, 事件委托
smallImg.onclick = function (e) {
  // 判断我点击的元素是li元素
  if (e.target.tagName == 'LI') {
    // 让所有li元素取消border
    let lis = $$('li');
    for (let i = 0; i < lis.length; i++) {
      lis[i].style.border = 'none';
    }
    // 让选中的li元素添加border
    e.target.style.border = '2px solid #000';

    // 点击缩略图后,原图和大图也需要跟着变换,
    // 点的是第几个元素, 获取元素索引
    // [1,2,3].indexOf(3) == 2
    let index = [].indexOf.call(lis, e.target);
    midImg.style.backgroundImage = 'url(./images/' + imgs.middle[index] + ')';
    largeImg.style.backgroundImage = 'url(./images/' + imgs.large[index] + ')';
  }
}

// 函数封装,一键启动
// 函数本质:若干步骤的集合
// 初始化页面函数
function initPage() {
  var str = '';
  for (let i = 0; i < imgs.small.length; i++) {
    str += '<li style="background-image: url(./images/' + imgs.small[i] + ');"></li>'
  }
  smallImg.innerHTML = str;
  // 2. 默认选中第一个缩略图
  $('.img-list li').style.border = '2px solid #000';
}

// 绑定事件
function bindEvent() {
  midImg.onmousemove = function (e) {
    // 让遮罩层和大图展示
    mask.style.opacity = 1;
    largeImg.style.opacity = 1;

    // 根据鼠标位置计算遮罩层的位置
    let left = e.clientX - midImg.offsetLeft - mask.offsetWidth / 2;
    // 同理
    let top = e.clientY - midImg.offsetTop - mask.offsetHeight / 2;

    // 边界条件
    if (left <= 0) {
      left = 0;
    }
    if (top <= 0) {
      top = 0;
    }
    if (left >= midImg.offsetWidth - mask.offsetWidth) {
      left = midImg.offsetWidth - mask.offsetWidth
    }
    if (top >= midImg.offsetHeight - mask.offsetHeight) {
      top = midImg.offsetHeight - mask.offsetHeight
    }
    // 根据top和left调整mask的位置
    mask.style.left = left + 'px';
    mask.style.top = top + 'px';

    // 根据top 和 left,修改大图的位置,background-position-x
    largeImg.style.backgroundPositionX = -left + 'px';
    largeImg.style.backgroundPositionY = -top + 'px';

  }

  // 2. 移出
  midImg.onmouseleave = function (e) {
    // 让遮罩层和大图消失
    mask.style.opacity = 0;
    largeImg.style.opacity = 0;
  }
}

// 一键启动,执行一个函数
function main() {
  initPage();
  bindEvent();
}

main();

🌟写在最后 

本专栏将持续更新原生JS案例,提供一些工作中也能用上的一些小案例,详细讲解分析,提升JS开发水平与开发思路的积累,如果文中出现有瑕疵的地方各位通过评论或者私信联系我,我们一起进步,有兴趣的伙伴可以订阅一下:点击关注JS经典案例专栏

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Centos7安装ZK-UI管理界面安装|Maven|Git|

一: JDK1.8安装 参考: Centos7卸载|安装JDK1.8|Xshell7批量控制多个终端 二&#xff1a;Maven安装 2.1&#xff1a;下载maven安装包 maven 下载地址&#xff1a;https://mirror.bit.edu.cn/apache/maven/maven-3/ [rootwww ~]# mkdir -p /usr/local/maven [rootwww ~]# …

STM32+RTThread配置以太网无法ping通,无法获取动态ip的问题

记录一个非常蠢的问题&#xff0c;今天在移植rtthread的以太网驱动的时候出现无法获取动态ip的问题&#xff0c;问题如下&#xff1a; 设置为动态ip时不管是连接路由器还是电脑主机都无法ping通&#xff0c;也无法获取dns地址。 设置为静态ip时无法ping通主机。 使用wireshark…

Docker笔记

学习了神光大佬的《Nest 通关秘籍》后&#xff0c;对docker做了个笔记&#xff0c;并实操部署了一下个人项目&#xff0c;在此记录一下 是什么 Docker是一种开源的容器化平台&#xff0c;它可以将应用程序及其依赖项打包到一个可移植的容器中&#xff0c;使得应用程序能够在任…

java八股文面试[JVM]——JVM调优

知识来源&#xff1a; 【2023年面试】JVM性能调优实战_哔哩哔哩_bilibili

测试平台metersphere

metersphere可以做接口测试、UI测试、性能测试。 metersphere接口测试底层是jmeter&#xff0c;可以做API管理&#xff0c;快捷调试&#xff0c;接口用例管理&#xff0c;接口自动化场景执行一键选取用例范围&#xff0c;生成测试报告。 会用jmeter&#xff0c;metersphere会…

深入浅出AXI协议(3)——握手过程

一、前言 在之前的文章中我们快速地浏览了一下AXI4协议中的接口信号&#xff0c;对此我们建议先有一个简单的认知&#xff0c;接下来在使用到的时候我们还会对各种信号进行一个详细的讲解&#xff0c;在这篇文章中我们将讲述AXI协议的握手协议。 二、握手协议概述 在前面的文章…

VS的调试技巧

Visual Studiohttps://visualstudio.microsoft.com/zh-hans/vs/ 目录 1、什么是调试&#xff1f; 2、debug和release 3、调试 3.1、环境 3.2、 快捷键 3.2.1、F10和F11 3.2.2、ctrlF5 3.2.3、F5与F9 3.2.3.1、条件断点 3.3、监视和内存观察 3.3.1、监视 3.3.2、内存 …

多目标应用:基于多目标向日葵优化算法(MOSFO)的微电网多目标优化调度MATLAB

一、微网系统运行优化模型 参考文献&#xff1a; [1]李兴莘,张靖,何宇,等.基于改进粒子群算法的微电网多目标优化调度[J].电力科学与工程, 2021, 37(3):7 二、多目标向日葵优化算法 多目标向日葵优化算法&#xff08;Multi-objective sunflower optimization&#xff0c;MOS…

JavaScript基础语法01——初识JavaScript

哈喽&#xff0c;大家好&#xff0c;我是雷工&#xff01; 最近有项目用到KingFusion软件&#xff0c;由于KingFusion是B/S架构的客户端组态软件&#xff0c;因此在学习KingFusion产品时会涉及许多前端的知识。 像JavaScript语言就是需要用的&#xff0c;俗话说&#xff1a;活到…

Leedcode19. 删除链表的倒数第 N 个结点

给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[] 示例 3&#xff1a; 输入&#xff1…

java八股文面试[数据库]——MySQL索引的数据结构

知识点&#xff1a; 【2023年面试】mysql索引的基本原理_哔哩哔哩_bilibili 【2023年面试】mysql索引结构有哪些&#xff0c;各自的优劣是什么_哔哩哔哩_bilibili

哈希的应用——布隆过滤器

✅<1>主页&#xff1a;&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;数据结构——位图 ☂️<3>开发环境&#xff1a;Visual Studio 2022 &#x1f4ac;<4>前言&#xff1a;布隆过滤器是由布隆&#xff08;Burton Howard Bloom&…

论文解读:Image-Adaptive YOLO for Object Detection in Adverse Weather Conditions

发布时间&#xff1a;2022.4.4 (2021发布&#xff0c;进过多次修订) 论文地址&#xff1a;https://arxiv.org/pdf/2112.08088.pdf 项目地址&#xff1a;https://github.com/wenyyu/Image-Adaptive-YOLO 虽然基于深度学习的目标检测方法在传统数据集上取得了很好的结果&#xf…

Postman中参数区别及使用说明

一、Params与Body 二者区别在于请求参数在http协议中位置不一样。Params 它会将参数放入url中以&#xff1f;区分以&拼接Body则是将请求参数放在请求体中 后端接受数据: 二、body中不同格式 2.1 multipart/form-data key - value 格式输入&#xff0c;主要特点是可以上…

Fei-Fei Li-Lecture 16:3D Vision 【斯坦福大学李飞飞CV课程第16讲:3D Vision】

目录 P1 2D Detection and Segmentation P2 Video 2D time series P3 Focus on Two Problems P4 Many more topics in 3D Vision P5-10 Multi-View CNN P11 Experiments – Classification & Retrieval P12 3D Shape Representations P13--17 3D Shape Represen…

hadoop大数据集群中更换磁盘,balance的速度缓慢问题(解决)

hadoop大数据集群中更换磁盘&#xff0c;balance的速度缓慢问题&#xff08;解决&#xff09; 看现象只有4个bloucks在执行的 调整参数&#xff1a; 增大配置参数&#xff0c;观察重新负载的速度 修改配置文件 hdfs-site.xml dfs.datanode.balance.max.concurrent.moves100 …

多线程应用——单例模式

单例模式 文章目录 单例模式一.什么是单例模式二.如何实现1.口头实现2.利用语法特性 三.实现方式&#xff08;饿汉式懒汉式&#xff09;1.饿汉式2.懒汉式3.线程安全的单例模式4.双重检查锁5.禁止指令重排序 一.什么是单例模式 单例模式&#xff08;Singleton Pattern&#xff…

软件研发CI/CD流水线图解

当谈到现代软件开发流程时&#xff0c;持续集成&#xff08;Continuous Integration&#xff0c;简称CI&#xff09;和持续交付&#xff08;Continuous Delivery&#xff0c;简称CD&#xff09;是两个关键的实践。它们旨在加速开发流程、提高软件质量&#xff0c;并使软件发布更…

kafka架构和原理详解

Apache Kafka 是一个分布式流数据平台,用于高吞吐量、持久性、可扩展的发布和订阅消息。它具有高度的可靠性,被广泛用于构建实时数据流处理、日志收集和数据管道等应用。 基本架构 1. 主题(Topic): 主题是消息的逻辑分类生产者将消息发布到特定的主题中,而消费者可以订阅…

【spring】一文带你弄懂Spring Bean的生命周期(超详细,超级通俗易懂!!)

目录 首先让我们来回顾一下Spring中的Bean是什么 Bean的生命周期 然后让我们由浅及深的对Bean的创建过程进行了解 首先来看最核心的五步骤 然后让我们逐层递进&#xff0c;学习一下七步骤版本吧 现在我们就可以进一步了解十步骤的版本&#xff08;完整的生命周期&#xff…