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

Posted 林恒

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记录-JS简单实现购物车图片局部放大预览效果相关的知识,希望对你有一定的参考价值。

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

一、实现效果

二、代码实现

代码不多,先看一下 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" >
</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\',`$200px`)
        this.magnifyingGlassView.setAttribute(\'height\',`$200px`)
        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\',`$widthpx`)
            canvas.setAttribute(\'height\',`$heightpx`)
            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\',`$diffusionLengthpx`)
            this.smallCanvas.setAttribute(\'height\',`$diffusionLengthpx`)
        
        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:

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

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

这样跨域问题就解决了。

本文转载于:

https://juejin.cn/post/7201437314693906491

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

 

css+jquery 实现图片局部放大预览

            今天有时间开始动手,使用css+jquery实现了图片局部放大的组件,首先看看效果图:

          界面设计思路如下: 

   1.两个div,左边放图片的缩略图
2.在左边缩略图鼠标移动的时候,区域(效果图中的网格)
3.右边放大图div,背景为缩略图的大图,在鼠标移入缩略图中,通过获取鼠标的坐标,将右侧背景图片移动到跟鼠标坐标对应的位置
4.设计时尽量,获取原大图的尺寸,和缩略图视窗计算比例,更大精度的做到左侧缩略图上表示的区域,和右侧放大部分匹配

         本示例大部分编码在javascript脚本,以下列出各部分的源码: 

<div class="all-region">
    <div class="image-wrap">
<!--缩略图div-->
<div class="little-img"> <img src="./images/show-window/timg.jpg"> </div>
<!--图片放大div-->
<div class="large-img"> </div>
<!--缩略图上展示被放大的区域,网格区域-->
<div class="relative-region"></div> </div> </div>

        css:

    .all-region {
        width: 100%;
        height: auto;
    }

    .all-region .image-wrap {
        width: 1300px;
        margin: 0px auto;
        height: 300px;
        line-height: 300px;
        overflow: hidden;
        vertical-align: center;
        background: #FBFBFB;
        border-left: 1px solid #ebebeb;
        position: relative;
    }

    .image-wrap .little-img img {
        width: 600px;
        height: 300px;
    }

    .image-wrap .large-img {
        width: 600px;
        height: 300px;
        background-image: url("./images/show-window/timg.jpg");
        border: 1px solid transparent;
        background-size: inherit;
        background-repeat: no-repeat;
        background-position-x: 0px;
        background-position-y: 0px;
        position: relative;
        top: -301px;
        left: 605px;
        float: left;
        z-index: 10;
        opacity: 0;
        display: none;
        transition: opacity 2s linear;
        overflow: hidden;
    }
    .relative-region {
        background: linear-gradient(45deg, rgba(46, 46, 46, 0.5) 50%, transparent 0),
        linear-gradient(135deg, rgba(200, 200, 200, .5) 70%, transparent 0);
        display: none;
        position: relative;
        z-index: 99;
        background-size: 5px 5px;
    }

          Javascript:

class Elements {
        constructor() {
            //缩略图区域
            this.sourceImage = $(".little-img");
            //放大区域
            this.aimImage = $(".large-img");
            //视图图片,与图片实际尺寸比例
            this.sourceToAimRate = 0.01;
            //原图高度
            this.sourceHeight = 0;
            //原图宽度
            this.sourceWidth = 0;
            //视图高度,div的高度,本例是300px
            this.containerHeight = this.sourceImage.children().height();
            this.containerWidth = this.sourceImage.children().width();
            //鼠标在缩略图上的坐标 offsetX
            this.cursor_x = 0;
            this.cursor_y = 0;
            //标志被放大的区域
            this.region = $(".relative-region");

            this.mouseMove = this.mouseMove.bind(this);
            this.regionPosition = this.regionPosition.bind(this);
            this.regionMove = this.regionMove.bind(this);
            this.caculatorRate = this.caculatorRate.bind(this);
        }
        //计算原图尺寸,思路是内存加载原图,获得尺寸,并计算容器视图和原图的比例
        caculatorRate() {
            console.log(this.sourceImage.children().attr("src"));
            $("<img/>").attr("src", this.sourceImage.children().attr("src")).load((e) => {
                //let sourceImageWidth=e.target.width;
                this.sourceWidth = e.target.width;
                this.sourceHeight = e.target.height;
                //计算图片和容器的像素比例
                this.sourceToAimRate = this.sourceWidth / this.containerWidth;
            });
        }
        //鼠标在缩略图上移动时计算,放大图的背景位置,并且定位标识被放大的区域
        mouseMove(e) {
            //console.log(`x:${e.offsetX},y:${e.offsetY}`);
            //偏离region的位置
            //由于鼠标实际上是在标识被放大区域(网格区域)的div里面,所以通过e获取的实际上是缩略图内,网格标识的offsetX 要用网格区域的offsetX+offsetLeft-缩略图的offsetleft才是鼠标对应到缩略图上的位置
            let r_x = e.offsetX;
            let r_y = e.offsetY;

            let s_t = this.sourceImage.offset().top;
            let s_l = this.sourceImage.offset().left;

            let r_t = this.region.offset().top;
            let r_l = this.region.offset().left;

            let x = r_l - s_l + r_x;
            let y = r_t - s_t + r_y;

            //在原图上显示,被放大的区域
            let w = this.region.width();
            let h = this.region.height();

             //由于鼠标在网格区域的中心,所以在计算放大图的top和left的时候,实际是从网格的左上角位置
            this.cursor_x = (x - w / 2) * this.sourceToAimRate;
            this.cursor_y = (y - h / 2) * this.sourceToAimRate;
            if (this.cursor_x + this.containerWidth > this.sourceWidth) {
                this.cursor_x = this.sourceWidth - this.containerWidth;
            }
            if (this.cursor_y + this.containerHeight > this.sourceHeight) {
                this.cursor_y = this.sourceHeight - this.containerHeight;
            }
            if (this.cursor_y < 0) {
                this.cursor_y = 0;
            }
            if (this.cursor_x < 0) {
                this.cursor_x = 0;
            }
            this.aimImage.css({
                "background-position-x": -this.cursor_x + "px",
                "background-position-y": -this.cursor_y + "px"
            }); 
            this.regionMove(w, h, x, y); 
}
        regionPosition(r_w, r_h, e) {
            let left = e.offsetX - r_w / 2;
            let top = e.offsetY - r_h / 2; 
            if (left < 0) {
                left = 0;
            }
            if (left + r_w > this.containerWidth) {
                left = this.containerWidth - r_w;
            }
            if (top < 0) {
                top = 0;
            }
            if (top + r_h > this.containerHeight) {
                top = this.containerHeight - r_h;
            }
            this.region.css({
                "top": (top - this.containerHeight) + "px",
                "left": left+ "px",
                "cursor": "crosshair"
            });
        } 
        regionMove(r_w, r_h, x, y) {
            let left = x - r_w / 2;
            let top = y - r_h / 2;

            if (left < 0) {
                left = 0;
            }
            if (left + r_w > this.containerWidth) {
                left = this.containerWidth - r_w;
            }
            if (top < 0) {
                top = 0;
            }
            if (top + r_h > this.containerHeight) {
                top = this.containerHeight - r_h;
            }
            this.region.css({"top": (top - this.containerHeight) + "px", "left": left + "px"});
        }

        init() {
            this.caculatorRate();
            //鼠标移入缩略图区域,由缩略图区域的hover事件初始化,将鼠标放入网格区域的中心
            this.sourceImage.children().mouseover((e) => {
                this.aimImage.css({"display": "block", "opacity": "1"});
                let r_w = this.containerWidth / this.sourceToAimRate;
                let r_h = this.containerHeight / this.sourceToAimRate;
                let x = e.offsetX;
                let y = e.offsetY;
                this.regionPosition(r_w, r_h, e);
                this.region.css({"display": "block", "height": r_h + "px", "width": r_w + "px"});
            });
            //修复鼠标在region上,右侧放大区域闪动
            this.region.mousemove(this.mouseMove);
            this.region.mouseleave(() => {
                this.aimImage.css({"display": "none", "opacity": "0"});
                this.region.css({"display": "none"});
            });
        }
    } 
    $(function () {
        var e = new Elements();
        e.init();
    })

         由于原图是1920*1080不是缩略视窗严格的2:1,计算中有小数等原因,使网格标识的区域,和放大区域展示的完全匹配

         在下一篇将尝试,放大镜逆应用为缩小镜,实现图片裁剪的时候,标识裁剪的部分位于原图的位置和区域.

以上是关于记录-JS简单实现购物车图片局部放大预览效果的主要内容,如果未能解决你的问题,请参考以下文章

vue3使用useMouseInElement实现图片局部放大预览效果

js实现图片局部等比放大

图片放大预览效果实现

利用JS实现购物网站商品放大镜效果

原生JS实现放大镜效果

Pro3:js实现放大镜效果