翼度科技»论坛 编程开发 JavaScript 查看内容

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

3

主题

3

帖子

9

积分

新手上路

Rank: 1

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



一、实现效果


二、代码实现

代码不多,先看一下 HTML 里面结构很简单,初始化 MagnifyingGlass 对象来关联一个 IMG 标签来实现放大。
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. </head>
  6. <body>
  7.     <img id="clothes"  src="https://www.cnblogs.com/./clothes.jpg" alt="">
  8. </body>
  9.    
  10. </html>
复制代码
再看一下 MagnifyingGlass
  1. class MagnifyingGlass {
  2.     // 需要放大的图片
  3.     imgEl
  4.     // 放大预览视图
  5.     magnifyingGlassView
  6.     // 区域小图
  7.     smallCanvas
  8.     // 保存原图的像素值
  9.     originalPiexls = []
  10.     // 截流定时器
  11.     interceptionTimer = null
  12.     constructor(el){
  13.         if(el.tagName == 'IMG'){
  14.             this.imgEl = el
  15.             this.listenerImgLoadSucceeded()
  16.         }
  17.     }
  18.    
  19.     // 监听图片加载完成
  20.     async listenerImgLoadSucceeded(){
  21.         if(!this.imgEl.complete){
  22.             await new Promise((resolve)=>{
  23.             this.imgEl.onload = resolve
  24.         })
  25.     }
  26.    
  27.     // 添加鼠标事件
  28.     this.addMouseEvent()
  29.         // 创建一个放大预览视图
  30.         this.createMagnifyingGlassView()
  31.     }
  32.     // 创建一个放大预览视图
  33.     createMagnifyingGlassView(){
  34.         if(this.magnifyingGlassView){
  35.             this.magnifyingGlassView.remove()
  36.         }
  37.         this.magnifyingGlassView = document.createElement('canvas')
  38.         this.magnifyingGlassView.style.cssText = 'position: fixed;background:aliceblue;left:0;top:0;pointer-events:none;display:none'
  39.         this.magnifyingGlassView.setAttribute('width',`${200}px`)
  40.         this.magnifyingGlassView.setAttribute('height',`${200}px`)
  41.         let body = document.getElementsByTagName('body')[0]
  42.         body.appendChild(this.magnifyingGlassView)
  43.     }
  44.     // 添加鼠标事件
  45.     addMouseEvent(){
  46.         // 添加鼠标滑过事件
  47.         this.addMouseMoveToImageEl()
  48.         // 鼠标滑出事件
  49.         this.addMouseLeaveToImageEl()
  50.     }
  51.     // 添加鼠标滑过事件
  52.     addMouseMoveToImageEl(){
  53.         this.imgEl.onmousemove = (event)=>{
  54.             let x = event.clientX + this.getElementPosition(this.imgEl).left + 20
  55.             let y = event.clientY + this.getElementPosition(this.imgEl).top + 20
  56.             let position = { x, y }
  57.             // 截流
  58.             this.interceptionFunc(()=>{
  59.                 // 修改放大视图位置
  60.                 this.changeMagnifyingGlassViewPosition(position)
  61.                 // 获取需要放大的像素
  62.                 this.getNeedMasgnifyingGlassPiexl({clientX: (event.clientX - this.getElementPosition(this.imgEl).left),clientY: (event.clientY - this.getElementPosition(this.imgEl).top)})
  63.             })
  64.         }
  65.     }
  66.     //截流
  67.     interceptionFunc(cb){
  68.         if(this.interceptionTimer){
  69.             return
  70.         }
  71.         this.interceptionTimer = setTimeout(() => {
  72.             cb()
  73.             this.interceptionTimer = null
  74.         }, 20);
  75.     }
  76.     // 鼠标滑出事件
  77.     addMouseLeaveToImageEl(){
  78.         this.imgEl.onmouseleave = ()=>{
  79.             // 移除放大框
  80.             this.magnifyingGlassView.style.display = 'none'
  81.         }
  82.     }
  83.     // 修改放大视图位置
  84.     changeMagnifyingGlassViewPosition(position){
  85.         this.magnifyingGlassView.style.left = position.x + 'px'
  86.         this.magnifyingGlassView.style.top = position.y + 'px'
  87.         this.magnifyingGlassView.style.display = 'block'
  88.     }
  89.     // 获取元素在屏幕的位置
  90.     getElementPosition(element){
  91.         var top = element.offsetTop
  92.         var left = element.offsetLeft
  93.         var currentParent = element.offsetParent;
  94.         while (currentParent !== null) {
  95.             top += currentParent.offsetTop
  96.             left += currentParent.offsetLeft
  97.             currentParent = currentParent.offsetParent
  98.         }
  99.         return {top,left}
  100.     }
  101.    
  102.     // 保存原像素(操作像素点时候用)
  103.     async getOriginalPiexls(){
  104.         if(this.originalPiexls.length == 0){
  105.             var image = new Image();
  106.             image.src = this.imgEl.src;
  107.             // 等待IMG标签加载完成后保存像素值
  108.             await new Promise((resolve)=>{
  109.                 image.onload = resolve
  110.             })
  111.             let width = image.width
  112.             let height = image.height
  113.             let canvas = document.createElement('canvas')
  114.             canvas.setAttribute('width',`${width}px`)
  115.             canvas.setAttribute('height',`${height}px`)
  116.             var ctx = canvas.getContext("2d")
  117.             ctx.fillStyle = ctx.createPattern(image, 'no-repeat');
  118.             ctx.fillRect(0, 0, width, height);
  119.             try {
  120.                 //保存像素
  121.                 this.originalPiexls = ctx.getImageData(0,0,width,height)
  122.             } catch (error) {
  123.                 console.log(error)
  124.             }
  125.         }
  126.     }
  127.     // 获取需要放大的像素
  128.     async getNeedMasgnifyingGlassPiexl(event){
  129.         //获取原始像素
  130.         this.getOriginalPiexls()
  131.         //如果像素为空,不进行操作
  132.         if(this.originalPiexls.length == 0){
  133.             return
  134.         }
  135.         //获取待放大IMG的宽度,用来计算像素
  136.         let imageWidth = this.imgEl.offsetWidth
  137.         //获取当前鼠标点的范围
  138.         let diffusionLength = 100
  139.         //鼠标触点
  140.         let mouseX = event.clientX
  141.         let mouseY = event.clientY
  142.         //规定区域的上下、左右宽度
  143.         let sepX = parseInt(diffusionLength)
  144.         let sepY = parseInt(diffusionLength)
  145.         // 需要开始的点
  146.         let startPoint = {x:(mouseX - parseInt(sepX / 2.0)),y:(mouseY - parseInt(sepY / 2.0))}
  147.         // 需要结束的点
  148.         let endPoint = {x:(mouseX + parseInt(sepX / 2.0)),y:(mouseY + parseInt(sepY / 2.0))}
  149.         // 最终要展示的像素集合(乘以4是单一像素值宽度)
  150.         let finallyOriginalPiexls = new Uint8ClampedArray(sepX * sepY * 4)
  151.         let currentIndex = 0
  152.         //操作像素
  153.         for(let i = startPoint.y;i < endPoint.y;i++){
  154.             for(let j = startPoint.x; j < endPoint.x;j++){
  155.                 for(let k = 0;k < 4;k++){
  156.                     let index = (i * imageWidth + j) * 4 + k
  157.                     if(index > 0 && index < this.originalPiexls.data.length){
  158.                     // 超过宽度部分需要进行其他色值填充
  159.                     if(j < imageWidth){
  160.                         finallyOriginalPiexls[currentIndex] = this.originalPiexls.data[index]
  161.                     } else {
  162.                         finallyOriginalPiexls[currentIndex] = 199
  163.                     }
  164.                     } else {
  165.                         finallyOriginalPiexls[currentIndex] = 199
  166.                     }
  167.                     currentIndex += 1
  168.                 }
  169.             }
  170.         }
  171.         
  172.         //先绘制一个100*100单位长的小图
  173.         if(!this.smallCanvas){
  174.             this.smallCanvas = document.createElement('canvas')
  175.             this.smallCanvas.setAttribute('width',`${diffusionLength}px`)
  176.             this.smallCanvas.setAttribute('height',`${diffusionLength}px`)
  177.         }
  178.         let smallCtx = this.smallCanvas.getContext("2d")
  179.         //初始化ImageData
  180.         let finallyImageData = new ImageData(finallyOriginalPiexls,sepX,sepY)
  181.         // 当前范围内需要放大的像素
  182.         smallCtx.putImageData(finallyImageData,0,0,0,0,diffusionLength,diffusionLength)
  183.         let url = this.smallCanvas.toDataURL('image/jpeg',1)
  184.         
  185.         //将小图绘制到200*200的预览图上
  186.         var image = new Image();
  187.         image.src = url;
  188.         await new Promise((resolve)=>{
  189.             image.onload = resolve
  190.         })
  191.         var magnifyingGlassCtx = this.magnifyingGlassView.getContext("2d")
  192.         magnifyingGlassCtx.drawImage(image, 0,0,200,200);
  193.     }
  194. }
复制代码
上面的就是全部逻辑,实现方法肯定不是最优的,但是其中可以联想到通过像素点的操作实现任意效果。
三、获取像素信息跨域问题怎么解决?

可以启动一个 node 本地服务,首先见一个包含 index.jspackage.json 的入口文件的文件夹。
package.json 内容如下:
  1. {
  2.     "name": "youname",
  3.     "version": "1.0.0",
  4.     "description": "description",
  5.     "main": "index.js",
  6.     "scripts": {
  7.     "test": "node ./index.js"
  8.     },
  9.     "author": "wsl",
  10.     "license": "ISC",
  11.     "dependencies": {
  12.         "express": "^4.17.3",
  13.         "express-static": "^1.2.6",
  14.         "http": "^0.0.1-security"
  15.     }
  16. }
复制代码
index.js 内容如下:
  1. var express = require('express')
  2. var app = express()
  3. var http = require('http').Server(app)
  4. //公共页面访问设置
  5. app.use(express.static('www'))
  6. //开启服务
  7. http.listen(3000,function(){
  8.     console.log('开始了')
  9. })
复制代码
终端执行 npm install 后再执行启动服务命令 node ./index.js:
三、获取像素信息跨域问题怎么解决?


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

这样跨域问题就解决了。
本文转载于:

https://juejin.cn/post/7201437314693906491

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

 


来源:https://www.cnblogs.com/smileZAZ/p/17337784.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

上一篇: 执行上下文

下一篇: 执行上下文

举报 回复 使用道具