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

基于原生Javascript的放大镜插件的设计和实现

概要

本文主要介绍一个前端放大镜插件的设计和实现,该插件可以将图片的指定区域进行局部放大,插件运行不依赖任何第三方库,可以在Chrome或Edge的常见版本上运行。

基本功能

  1. 可以将图片中指定区域扩大1.5倍
  2. 放大镜可以跟随鼠标进行移动
  3. 放大镜或鼠标超出图片区域后自动隐藏
  4. 鼠标进入图片区域后,放大镜自动显现

在这里插入图片描述

设计和实现

将要放大的图片放置于指定区域和放大镜中,将放大镜放大的同时将图片中的指定区域进行放大,放大效果的主要通过css3的动画实现。

本文只介绍关键代码,其它代码请参考附录。

 <div class="magnifier" id="m1">
        <div class="magnifier-area">
            <img src="./images/1.jpeg">
        </div>
        <div class="static-area">
            <img src="./images/1.jpeg">
        </div>
    </div>

整个区域采用relative定位,magnifier-area和内部的图片采用绝对定位。static-area是图片的展示区域,直接继承父级元素的定位方式。

事件绑定

本文主要使用mouseover和mouseout两个事件

 bindEvent = () => {
        this.$magnifier.addEventListener("mouseover", (e)=> {
            this.$magArea.classList.add("active");
            document.addEventListener("mouseover", this.handleMouseover, false);
        }, false);

        this.$magnifier.addEventListener("mouseout",()=>{
            document.removeEventListener("mouseover", this.handleMouseover, false);
        }, false);
    }

在鼠标进入图片区域后,为document绑定mouseover事件,将放大镜区域按照原始长宽的1.5倍显示出来,并随鼠标一起运动。

在鼠标离开图像区域后,为document解绑mouseover事件,隐藏放大镜。

坐标运算

放大镜要在图片区域跟着鼠标一起移动,需要计算鼠标在图片区域内的坐标和放大镜中心点在图片区域内的坐标。

在这里插入图片描述
如上图所示,首先我们计算鼠标相对于图片区域的位置,

x = 鼠标的页面坐标(pageX)- 图片左侧和页面间的边距(蓝线)
同理
y = 鼠标的页面坐标(pageY)- 图片顶端和页面间的边距

计算放大镜左上角(橙色点)的坐标

x = 鼠标的页面坐标(pageX)- 图片左侧和页面间的边距(蓝线)- 放大镜区域长度的一半(绿线)
同理
y = 鼠标的页面坐标(pageY)- 图片顶端和页面间的边距 - 放大镜区域高度的一半

 handleMouseover = (e) => {
        const {mousePoint, magPoint} = this.getPointByMouse(e);
        this.moveToMousePoint(magPoint);
        if (this.checkOutMagArea(mousePoint)){
            this.$magArea.classList.remove("active");
            document.removeEventListener("mouseover", this.handleMouseover, false);
        }  
    moveToMousePoint(mousePoint){
        this.$magArea.style.left = `${mousePoint.x}px`;
        this.$magArea.style.top = `${mousePoint.y}px`;
        this.$magImg.style.left = `-${mousePoint.x}px`;
        this.$magImg.style.top = `-${mousePoint.y}px`;
    }
  1. 在mouseover的绑定方法handleMouseover中,首先调用getPointByMouse方法,按照上述公式,计算鼠标和放大镜的相对坐标;
  2. 调用moveToMousePoint方法,移动放大镜和放大镜中的图片,二者移动方向相反,才能保证是同一块区域被放大;
  3. 检查鼠标是否在图片区域内,如果不在,隐藏放大镜,解绑mouseover事件。

附录

<!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">
    <link rel="stylesheet" href="style.css">
    <script src="./magnifier.js" defer></script>
    <title>Magnifier</title>
</head>
<body>
    <div class="magnifier" id="m1">
        <div class="magnifier-area">
            <img src="./images/1.jpeg">
        </div>
        <div class="static-area">
            <img src="./images/1.jpeg">
        </div>
    </div>
</body>
</html>
class Magnifier {
    constructor(options){
        this.$magnifier = document.querySelector(options.el);
        this.$magArea = this.$magnifier.querySelector("div.magnifier-area");
        const {width, height, top, left} = this.$magnifier.getBoundingClientRect();
        this.magnifierWidth = width;
        this.magnifierHeight = height;
        this.magnifierLeft = left;
        this.magnifierTop = top;
        const magAreaStyle = getComputedStyle(this.$magArea);
        this.magAreaWdith = parseInt(magAreaStyle.width);
        this.magAreaHeight = parseInt(magAreaStyle.height);
        this.$magImg = this.$magArea.querySelector("img");
        this.init();
    }
    init = ()=> {
        this.bindEvent();
    }
    bindEvent = () => {
        this.$magnifier.addEventListener("mouseover", (e)=> {
            this.$magArea.classList.add("active");
            document.addEventListener("mouseover", this.handleMouseover, false);
        }, false);

        this.$magnifier.addEventListener("mouseout",()=>{
            document.removeEventListener("mouseover", this.handleMouseover, false);
        }, false);
    }

    getPointByMouse = (mouse) => {
        const x = mouse.pageX - this.magnifierLeft - this.magAreaWdith / 2;
        const y = mouse.pageY - this.magnifierTop - this.magAreaHeight / 2;
        const xMouse = mouse.pageX - this.magnifierLeft;
        const yMouse = mouse.pageY - this.magnifierTop;
        console.log( mouse.pageX, this.magnifierLeft);
        return {
            magPoint: new Point(x,y),
            mousePoint: new Point(xMouse, yMouse)
        };
    }
    moveToMousePoint(mousePoint){
        this.$magArea.style.left = `${mousePoint.x}px`;
        this.$magArea.style.top = `${mousePoint.y}px`;
        this.$magImg.style.left = `-${mousePoint.x}px`;
        this.$magImg.style.top = `-${mousePoint.y}px`;
    }
    checkOutMagArea (mousePoint){
        return (mousePoint.x < 0 ||  
            mousePoint.y < 0  || 
            mousePoint.x >= this.magnifierWidth ||
            mousePoint.y >= this.magnifierHeight) ;
    }
    handleMouseover = (e) => {
        const {mousePoint, magPoint} = this.getPointByMouse(e);
        this.moveToMousePoint(magPoint);
        if (this.checkOutMagArea(mousePoint)){
            this.$magArea.classList.remove("active");
            document.removeEventListener("mouseover", this.handleMouseover, false);
        }  
        
    }
 
}

class Point {
    constructor(x,y){
        this.x = x;
        this.y = y;
    }
}
new Magnifier({
    el:'#m1'
});
*{
    margin: 0;
    top: 0;
}
.magnifier{
    position: relative;
    width: 600px;
    height: 800px;
    margin: 100px auto;
    .magnifier-area {
        position: absolute;
        left: 0;
        top: 0;
        width: 100px;
        height: 100px;
        border-radius: 50%;
        z-index: 3;
        overflow: hidden;
        display: none;
        box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
        backdrop-filter: blur(5px);
        border: 1px solid rgba(255, 255, 255, 0.3);
        cursor: move;
        &.active {
            display: block;
            transform: scale(1.5);
        }
        img {
            position: absolute;
            left: 0;
            top: 0;
            width: 600px;
            height: 800px; 
        }
    }
    .static-area{
        width: 100%;
        height: 100%;
        img {
            width: 100%;
            height: 100%;
        }
    }
}

http://www.kler.cn/a/2848.html

相关文章:

  • RustDesk内置ID服务器,Key教程
  • 面试突击-JAVA集合类(持续更新...)
  • Semantic Segmentation Editor标注工具
  • day26 文件io
  • 使用 .NET 6 或 .NET 8 上传大文件
  • 决策树python实现代码1
  • 贪心算法(一)
  • 蓝桥杯刷题冲刺 | 倒计时18天
  • MD5加密竟然不安全,应届生表示无法理解?
  • Java每日一练(20230324)
  • hive之视图
  • 手写一个Promise
  • maya python 中的maya.cmds 与maya.mel模块的区别笔记
  • 新闻文本分类任务:使用Transformer实现
  • A.机器学习入门算法(六)基于天气数据集的XGBoost分类预测
  • 用嘴写代码?继ChatGPT和NewBing之后,微软又开始整活了,Github Copilot X!
  • 【史上最全面esp32教程】oled显示篇
  • 第十四届蓝桥杯三月真题刷题训练——第 21 天
  • 【尝鲜版】ChatGPT插件开发指南
  • 二维图像处理到三维点云处理
  • 嵌入式系统 - 对话
  • LInux下安装libreoffice(用于Linux下Word转pdf,附代码)
  • 无需公网IP,远程连接SQL Server数据库【内网穿透】
  • 【Unityc#专题篇】之c#基础篇
  • ASO优化之应用商店中的A/B测试——改良版
  • 菜鸟刷题Day5