记录-JS简单实现购物车图片局部放大预览效果

news2025/1/15 20:51:17

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

一、实现效果

屏幕录制2023-02-18 下午8.21.50.gif

二、代码实现

代码不多,先看一下 HTML 里面结构很简单,初始化 MagnifyingGlass 对象来关联一个 IMG 标签来实现放大。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<style type="text/css">
*{
    padding: 0;
    margin: 0;
}

.clothes {
    width: auto;
    height: auto;
}
</style>

<body>
<div>
    <img id="clothes" class="clothes" src="./clothes.jpg" alt="">
</div>
</body>
    <script src="./magnifyingGlass.js"></script>
<script>
    //针对某个标签进行图片放大处理
    let magnifyingGlass = new MagnifyingGlass(document.getElementById('clothes'))
</script>

</html>

再看一下 MagnifyingGlass

class MagnifyingGlass {

    // 需要放大的图片
    imgEl
    // 放大预览视图
    magnifyingGlassView
    // 区域小图
    smallCanvas
    // 保存原图的像素值
    originalPiexls = []
    // 截流定时器
    interceptionTimer = null

    constructor(el){
        if(el.tagName == 'IMG'){
            this.imgEl = el
            this.listenerImgLoadSucceeded()
        }
    }
    
    // 监听图片加载完成
    async listenerImgLoadSucceeded(){
        if(!this.imgEl.complete){
            await new Promise((resolve)=>{
            this.imgEl.onload = resolve
        })
    }
    
    // 添加鼠标事件
    this.addMouseEvent()
        // 创建一个放大预览视图
        this.createMagnifyingGlassView()
    }

    // 创建一个放大预览视图
    createMagnifyingGlassView(){
        if(this.magnifyingGlassView){
            this.magnifyingGlassView.remove()
        }
        this.magnifyingGlassView = document.createElement('canvas')
        this.magnifyingGlassView.style.cssText = 'position: fixed;background:aliceblue;left:0;top:0;pointer-events:none;display:none'
        this.magnifyingGlassView.setAttribute('width',`${200}px`)
        this.magnifyingGlassView.setAttribute('height',`${200}px`)
        let body = document.getElementsByTagName('body')[0]
        body.appendChild(this.magnifyingGlassView)
    }

    // 添加鼠标事件
    addMouseEvent(){
        // 添加鼠标滑过事件
        this.addMouseMoveToImageEl()
        // 鼠标滑出事件
        this.addMouseLeaveToImageEl()
    }

    // 添加鼠标滑过事件
    addMouseMoveToImageEl(){
        this.imgEl.onmousemove = (event)=>{
            let x = event.clientX + this.getElementPosition(this.imgEl).left + 20
            let y = event.clientY + this.getElementPosition(this.imgEl).top + 20
            let position = { x, y }
            // 截流
            this.interceptionFunc(()=>{
                // 修改放大视图位置
                this.changeMagnifyingGlassViewPosition(position)
                // 获取需要放大的像素
                this.getNeedMasgnifyingGlassPiexl({clientX: (event.clientX - this.getElementPosition(this.imgEl).left),clientY: (event.clientY - this.getElementPosition(this.imgEl).top)})
            })
        }
    }

    //截流
    interceptionFunc(cb){
        if(this.interceptionTimer){
            return
        }
        this.interceptionTimer = setTimeout(() => {
            cb()
            this.interceptionTimer = null
        }, 20);
    }

    // 鼠标滑出事件
    addMouseLeaveToImageEl(){
        this.imgEl.onmouseleave = ()=>{
            // 移除放大框
            this.magnifyingGlassView.style.display = 'none'
        }
    }

    // 修改放大视图位置
    changeMagnifyingGlassViewPosition(position){
        this.magnifyingGlassView.style.left = position.x + 'px'
        this.magnifyingGlassView.style.top = position.y + 'px'
        this.magnifyingGlassView.style.display = 'block'
    }

    // 获取元素在屏幕的位置
    getElementPosition(element){
        var top = element.offsetTop
        var left = element.offsetLeft
        var currentParent = element.offsetParent;
        while (currentParent !== null) {
            top += currentParent.offsetTop
            left += currentParent.offsetLeft
            currentParent = currentParent.offsetParent
        }
        return {top,left}
    }
    
    // 保存原像素(操作像素点时候用)
    async getOriginalPiexls(){
        if(this.originalPiexls.length == 0){
            var image = new Image();
            image.src = this.imgEl.src;
            // 等待IMG标签加载完成后保存像素值
            await new Promise((resolve)=>{
                image.onload = resolve
            })
            let width = image.width
            let height = image.height
            let canvas = document.createElement('canvas')
            canvas.setAttribute('width',`${width}px`)
            canvas.setAttribute('height',`${height}px`)
            var ctx = canvas.getContext("2d")
            ctx.fillStyle = ctx.createPattern(image, 'no-repeat');
            ctx.fillRect(0, 0, width, height);
            try {
                //保存像素
                this.originalPiexls = ctx.getImageData(0,0,width,height)
            } catch (error) {
                console.log(error)
            }
        }
    }

    // 获取需要放大的像素
    async getNeedMasgnifyingGlassPiexl(event){
        //获取原始像素
        this.getOriginalPiexls()
        //如果像素为空,不进行操作
        if(this.originalPiexls.length == 0){
            return
        }
        //获取待放大IMG的宽度,用来计算像素
        let imageWidth = this.imgEl.offsetWidth
        //获取当前鼠标点的范围
        let diffusionLength = 100
        //鼠标触点
        let mouseX = event.clientX
        let mouseY = event.clientY
        //规定区域的上下、左右宽度
        let sepX = parseInt(diffusionLength)
        let sepY = parseInt(diffusionLength)
        // 需要开始的点
        let startPoint = {x:(mouseX - parseInt(sepX / 2.0)),y:(mouseY - parseInt(sepY / 2.0))}
        // 需要结束的点
        let endPoint = {x:(mouseX + parseInt(sepX / 2.0)),y:(mouseY + parseInt(sepY / 2.0))}
        // 最终要展示的像素集合(乘以4是单一像素值宽度)
        let finallyOriginalPiexls = new Uint8ClampedArray(sepX * sepY * 4)
        let currentIndex = 0
        //操作像素
        for(let i = startPoint.y;i < endPoint.y;i++){
            for(let j = startPoint.x; j < endPoint.x;j++){
                for(let k = 0;k < 4;k++){
                    let index = (i * imageWidth + j) * 4 + k
                    if(index > 0 && index < this.originalPiexls.data.length){
                    // 超过宽度部分需要进行其他色值填充
                    if(j < imageWidth){
                        finallyOriginalPiexls[currentIndex] = this.originalPiexls.data[index]
                    } else {
                        finallyOriginalPiexls[currentIndex] = 199
                    }
                    } else {
                        finallyOriginalPiexls[currentIndex] = 199
                    }
                    currentIndex += 1
                }
            }
        }
        
        //先绘制一个100*100单位长的小图
        if(!this.smallCanvas){
            this.smallCanvas = document.createElement('canvas')
            this.smallCanvas.setAttribute('width',`${diffusionLength}px`)
            this.smallCanvas.setAttribute('height',`${diffusionLength}px`)
        }
        let smallCtx = this.smallCanvas.getContext("2d")
        //初始化ImageData
        let finallyImageData = new ImageData(finallyOriginalPiexls,sepX,sepY)
        // 当前范围内需要放大的像素
        smallCtx.putImageData(finallyImageData,0,0,0,0,diffusionLength,diffusionLength)
        let url = this.smallCanvas.toDataURL('image/jpeg',1)
        
        //将小图绘制到200*200的预览图上
        var image = new Image();
        image.src = url;
        await new Promise((resolve)=>{
            image.onload = resolve
        })
        var magnifyingGlassCtx = this.magnifyingGlassView.getContext("2d")
        magnifyingGlassCtx.drawImage(image, 0,0,200,200);
    }
}

上面的就是全部逻辑,实现方法肯定不是最优的,但是其中可以联想到通过像素点的操作实现任意效果。

三、获取像素信息跨域问题怎么解决?

可以启动一个 node 本地服务,首先见一个包含 index.jspackage.json 的入口文件的文件夹。

package.json 内容如下:

{
    "name": "youname",
    "version": "1.0.0",
    "description": "description",
    "main": "index.js",
    "scripts": {
    "test": "node ./index.js"
    },
    "author": "wsl",
    "license": "ISC",
    "dependencies": {
        "express": "^4.17.3",
        "express-static": "^1.2.6",
        "http": "^0.0.1-security"
    }
}

index.js 内容如下:

var express = require('express')
var app = express()
var http = require('http').Server(app)
//公共页面访问设置
app.use(express.static('www'))
//开启服务
http.listen(3000,function(){
    console.log('开始了')
})

终端执行 npm install 后再执行启动服务命令 node ./index.js:

三、获取像素信息跨域问题怎么解决?

image.png

注意将前端文件放在目录里 www 文件夹下

image.png

这样跨域问题就解决了。

本文转载于:

https://juejin.cn/post/7201437314693906491

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 

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

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

相关文章

做一个网站需要多少个技术人员?

作为互联网从业者&#xff0c;这么多年来经常会碰到一个灵魂拷问&#xff0c;那就是“为什么一个网站需要那么多技术人员&#xff1f;”&#xff0c;尤其是提问者如果再追问一下“听说几个相关专业的学生一个课程的作业就是开发一个网站或者app&#xff0c;那为什么现在主流的网…

C++ | 认识标准库string和vector

本文概要 本篇文章主要介绍C的标准库类型string和vector&#xff0c;文中描述和代码示例很详细&#xff0c;看完即可掌握&#xff0c;感兴趣的小伙伴快来一起学习吧。 &#x1f31f;&#x1f31f;&#x1f31f;个人简介 &#x1f31f;&#x1f31f;&#x1f31f; ☀️大家好&a…

stable diffusion安装从0到1总结:包括遇到的坑和步骤

注&#xff1a;最低电脑配置&#xff1a;8G Vram16G RAM30G磁盘空间以上&#xff0c;20系列显卡及以上&#xff0c;windows>linux>macos。 文件可以不放在系统盘。举个例子&#xff1a;安装在D盘&#xff0c;在D盘创建一个StableDiffusion文件夹。下载下面文件: 1.下载…

为什么实现 API 最佳实践需要重新考虑安全性

随着应用程序编程接口 (API) 的使用与日俱增&#xff0c;实现和维护有效安全性的挑战从未像现在这样大。 由于缺乏管理 API 的单一标准&#xff0c;这意味着团队不能仅依靠工具来解决安全问题&#xff0c;因此这一挑战变得更加严峻。没有任何一种产品可以解决 API 环境的每种…

pg编码相关问题梳理

Lightdb/PG 编码相关问题梳理 之前在通过SQL文件导入数据时&#xff0c;报&#xff1a;ERROR: invalid byte sequence for encoding "EUC_CN"错误。然后就梳理了一下编码相关问题&#xff0c;这边记录一下。涉及到如下两种类型的报错&#xff1a; ERROR: invalid b…

电脑如何还原系统?这样做可以快速解决!

案例&#xff1a;我的电脑系统出问题了&#xff0c;怎么还原&#xff1f; 【我的电脑用了好几年了&#xff0c;最近它的系统出现了一些问题&#xff0c;我想还原电脑系统。有没有知道电脑系统如何还原&#xff1f;蹲一个简单的解决方法&#xff01;】 随着电脑使用时间的增加…

面试华为,花了2个月才上岸,真的难呀····

花2个月时间面试一家公司&#xff0c;你们觉得值吗&#xff1f; 背景介绍 美本计算机专业&#xff0c;代码能力一般&#xff0c;之前有过两段实习以及一个学校项目经历。第一份实习是大二暑期在深圳的一家互联网公司做前端开发&#xff0c;第二份实习由于大三暑假回国的时间比…

Linux中的git命令行

Linux中的git命令行 目录 Linux中的git命令行引入1、Linux下的git工具起源2、gitee的使用.gitignore.git 3、git三板斧3.1 git add3.2 git commit3.3 git push 4、git操作4.1 查看提交日志4.2 查看状态4.3 远端同步4.4 删除文件4.5 修改文件名 引入 当多个开发者同时参与同一个…

(一)Jhipster的基本介绍及入门安装

目录 1、为什么要使用 Jhipster &#xff1f; 2、安装配置 3、安装Jhipster 4、基本使用 5、介绍一下JDL Studio 6、启动 Jhipster 搭建项目 1、为什么要使用 Jhipster &#xff1f; JHipster是一个开发平台&#xff0c;可以快速生成、开发和部署现代Web应用程序和微服务…

分享几个自动化测试的练手项目

学习自动化测试最难的是没有合适的项目练习。 测试本身既要讲究科学&#xff0c;又有艺术成分&#xff0c;单单学几个 api 的调用很难应付工作中具体的问题。 你得知道什么场景下需要添加显性等待&#xff0c;什么时候元素定位需要写得更加优雅&#xff0c;为什么需要断言这个…

CANoe使用记录(四):CANoe Graphics图形窗口

目录 1、概述 2、Graphics图形窗口 2.1、打开测量窗口&#xff08;回放Log&#xff09; 2.2、输出Log 2.3、添加解析DBC文件 2.4、窗口排列 2.5、添加Graphics窗口 2.6、 信号栏选择 2.7、添加信号 2.8、波形样式 2.9、单Y轴测量尺 2.10、多Y轴测量尺 2.11、数据隐…

10行Python代码,助你整理杂乱无章的文件

朋友们好&#xff0c;今天是周五&#xff0c;又到了快放假的时间&#xff0c;激不激动&#xff1f;高不高兴&#xff1f;但是我还是要继续分享 Python 小工具给大家&#xff0c;嘻嘻~~ 今天的小程序&#xff0c;可以一键完成文件整理&#xff0c;一起来看看吧&#xff01; 按…

API 接口主流协议有哪些? 如何创建不同协议?

API 接口协议繁多&#xff0c;不同的协议有着不同的使用场景。70% 互联网应用开发者日常仅会接触到最通用的 HTTP 协议&#xff0c;相信大家希望了解更多其他协议的信息。我们今天会给大家介绍各种 API 接口主流协议和他们之间的关系。 1、API 接口主流协议有哪些? 接口协议分…

java环境安装 以jdk1.8 tomcat8为例

1、选择相应版本下载 官网地址&#xff1a;http://www.oracle.com/technetwork/java/javase/downloads/index.html 2、下载后一直点击下一步就好了ps&#xff1a;路径不喜欢安装在C盘的可以选择其他盘符&#xff0c;但是一定要自己找的到安装路径。 3、选择路径安装jdk1.8 4、…

Java基础(十六):String的常用API

Java基础系列文章 Java基础(一)&#xff1a;语言概述 Java基础(二)&#xff1a;原码、反码、补码及进制之间的运算 Java基础(三)&#xff1a;数据类型与进制 Java基础(四)&#xff1a;逻辑运算符和位运算符 Java基础(五)&#xff1a;流程控制语句 Java基础(六)&#xff1…

Serilog介绍

SerilogSerilogSerilog是.net 下的新兴的日志框架&#xff0c;本文这里简单的介绍一下它的用法。 首先安装Nuget包&#xff1a; Install-Package SerilogInstall-Package Serilog.Sinks.Console 其中包Serilog是Log核心库&#xff0c;Serilog.Sinks.Console是Log的控制台输出…

云安全问题及其解决方案

随着云计算技术的快速发展&#xff0c;云计算已经成为了企业和个人的首选。云计算在提高了企业的效率和降低了成本的同时&#xff0c;也带来了一系列的安全问题。本篇博客将深入讨论云安全问题&#xff0c;并提出相应的解决方案&#xff0c;以帮助企业和个人更好地保护自己的云…

【C++学习笔记】对象的特性

深拷贝与浅拷贝 浅拷贝&#xff1a;简单的赋值拷贝操作 深拷贝&#xff1a;在堆区重新申请空间&#xff0c;进行拷贝 利用编译器提供的拷贝构造函数&#xff0c;会做浅拷贝操作&#xff1b;会导致堆区的内存重复释放 ![[Pasted image 20221216213144.png]] 解决方法&#xff…

Qt/QML编程学习之心得:跨平台(一)

Qt作为Cross-platform的一种开发语言,在GUI界面设计上俘获了大批开发者。 Qt很年轻但是也不年轻,看下它创作公司的历史就知道了: › 1994: Troll Tech. First public release in 1995 › 2008: Nokia acquires Troll Tech › 2012: Digia buys Qt from Nokia › 01.05.2016:…

有反爬机制就爬不了吗?那是你还不知道反反爬,道高一尺魔高一丈啊

文章目录 一、从用户请求的Headers反爬虫二、基于用户行为反爬虫&#xff08;1&#xff09;方法1&#xff08;2&#xff09;方法2 三、动态页面的反爬虫四.总结 不知道你们在用爬虫爬数据的时候是否有发现&#xff0c;越来越多的网站都有自己的反爬机制&#xff0c;抓取数据已经…