美文网首页JQueryWeb前端之路Web 前端开发
javascript实现放大镜插件【含进阶】

javascript实现放大镜插件【含进阶】

作者: 顽皮的雪狐七七 | 来源:发表于2017-07-04 16:00 被阅读506次

    [目录]

    • 【简单的实现放大镜动能】
    • 成果图
    • 放大镜的原理
    • 网页结构
    • 实现步骤
      • 第一步 获取元素
      • 第二步 注册鼠标进入离开事件
      • 第三步 注册鼠标移动事件(确定遮罩层的定位)
      • 最后一步 大图跟着鼠标移动
    • 整理一下全部的js代码
    • 【放大镜进阶】
      • 功能分析
      • 效果图
      • 截屏插件html2canvas
        • 注意事项
        • 可用参数
        • demo
      • 放大镜的html结构
      • 使用jquery进行代码实现
        • 第一步 获取元素
        • 第二步 注册按钮点击事件
        • 第三步 截屏功能
        • 第四步 注册鼠标移动事件(移动大图)
        • 第五步 给屏幕上动态的添加元素
      • 完整代码
      • 补充

    放大镜在网页中运用广泛,在淘宝京东上面的商品图中就用到了,还有在空间上面展示图片的地方也有用到。现在这种jquery的插件也有很多,但是也要明白其中原理就可以自己做各种各样的放大镜效果了。
    现在就来好好分析一下放大镜的原理和实现的过程:

    简单的实现

    成果图:

    图像 1.png

    放大镜的原理

    使用两个图片,一个是小图——全部展现在页面中的,一个是大图——局部展示放大的效果。所以由此可以看出突破点,就是网页中一共有两张图,根据他们的移动的距离,可以实现放大镜的效果。

    网页结构

    下面就来写以下网页的结构

    <!--css样式-->
      <style>
           * {
               margin: 0;
               padding: 0;
           }
           /*放大镜的大盒子*/
           .box {
               width: 350px;
               height: 350px;
               margin: 100px;
               border: 1px solid #ccc;
               position: relative;
           }
           /*大图片外面的盒子*/
           .big {
               width: 400px;
               height: 400px;
               position: absolute;
               top: 0;
               left: 360px;
               border: 1px solid #ccc;
               overflow: hidden;
               display: none;
           }
           /*遮挡层*/
           .mask {
               width: 175px;
               height: 175px;
               background: rgba(255, 255, 0, 0.4);
               position: absolute;
               top: 0px;
               left: 0px;
               cursor: move;
               display: none;
           }
           /*小图片外面的大盒子*/
           .small {
               position: relative;
           }
       </style>
    
    
    
    <!--html结构-->
    <body>
    
     <!--放大镜的整体-->
     <div class="box" id="box">
         <!--小图的模块-->
         <div class="small">
             <!--小图-->
             ![](images/small.png)
             <!--遮挡层-->
             <div class="mask"></div>
         </div>
    
         <!--大图的模块-->
         <div class="big">
              <!--大图-->
             ![](images/big.jpg)
         </div>
     </div>
    </body>
    

    如果上面的骨架搭好了,下面就来分析以下放大镜的功能步骤:
    1.鼠标移动的时候遮罩层中的框也跟着一起移动
    2.在遮罩层移动的时候右边的大图也一起移动
    3.遮罩层的移动和大图的移动是相反的,也是按照一定比例进行移动的
    4.遮罩层是不能离开小图的框的

    实现步骤

    下面上步骤:

    第一步 获取元素

    因为这里面的元素都有可能用到

         //获取最外面的div
        var box = document.getElementById("box");
        //获取显示小图的div
        var small = box.children[0];
        //获取小图中的遮挡的div
        var mask = small.children[1];
        //获取显示大图的div
        var big = box.children[1];
        //获取大div中的大图
        var imgObj = big.children[0];
    

    第二步 注册鼠标进入离开事件

    在鼠标进入的时候,显示遮挡层和大图的图层
    在鼠标离开的时候,隐藏遮挡层和大图的图层

          //鼠标进入事件
          box.onmouseover = function(){
                   mask.style.display = "block";
                   big.style.display = "block";
          }
          //鼠标离开事件
          box.onmouseout = function(){
                   mask.style.display = "none";
                   big.style.display = "none";
          }
    

    第三步 注册鼠标移动事件(确定遮罩层的定位)

    给鼠标注册移动事件,在小图上移动的时候,遮罩层也跟着移动

    • 要拿到可视区域的横纵坐标——clientX,clientY(不考虑兼容性)
    • 设置遮罩层的left和top值
      那么怎么通过鼠标的横纵坐标来设置遮罩层的left和top的值呢?
      一张图来说明白:
    mask.png

    上图中的第三步,分析为什么会出现这样的问题
    因为在鼠标进入的时候,在鼠标和小图的框中加了一个遮罩层,这个遮罩层让鼠标和小图的框进行了分离。所以当鼠标进行移动的时候,移动到了小图的框的外面,但是检测不到鼠标到底有没有离开小图的范围,所以遮罩层就跟着鼠标一起可以在可视区域中进行移动。
    要想要进行范围的限定,就类似于一辆车在两堵墙之间的移动的最大距离一样。最大的移动距离无非就是小图框本身的宽度 - 遮罩层本身的宽度

    下面上代码:

    small.onmousemove = function (e) {
            var left = e.clientX - mask.offsetWidth / 2;//横坐标
            var top = e.clientY - mask.offsetHeight / 2;//纵坐标
            //设置遮挡层的left和top
            var x = left - 100;//margin
            var y = top - 100;//margin
    
            //为遮挡层设置范围
            x=x<0?0:x;//如果横坐标小于0就设置为0
            y=y<0?0:y;//如果纵坐标小于0就设置为0
    
            //如果横坐标大于横向最大移动距离就设置为横向最大移动距离
            x=x>small.offsetWidth-mask.offsetWidth?small.offsetWidth-mask.offsetWidth:x;
            //如果纵坐标大于纵向最大移动距离就设置为纵向最大移动距离
            y=y>small.offsetHeight-mask.offsetHeight?small.offsetHeight-mask.offsetHeight:y;
            
            //设置mask的定位
            mask.style.left = x + "px";
            mask.style.top = y + "px";
        };
    
    

    最后一步 大图跟着鼠标移动

    • 如果图片是有比例的,那么移动的时候也成比例就可以
    • 如果图片是不成比例的,那么就要有一个普遍的算法
      先来个原理图:
    max.png

    上图说的是宽度,其实高度可以以此类推。
    由此可以得出:
    **大图的移动距离 = 遮挡层的移动距离 * 大图的最大移动距离 / 遮挡层的最大移动距离 **

            //大图的最大的移动距离
            var imgMaxMove=imgObj.offsetWidth-big.offsetWidth;
            //遮挡层的最大的移动距离
            var maskMaxMove=small.offsetWidth-mask.offsetWidth;
            //大图的横向移动的距离
            var imgMoveLeft=x*imgMaxMove/maskMaxMove;
            //大图的纵向移动的距离
            var imgMoveTop=y*imgMaxMove/maskMaxMove;
    
            //设置大图的left和top---移动的是margin-left和margin-top
    
            imgObj.style.marginLeft=-imgMoveLeft+"px";
            imgObj.style.marginTop=-imgMoveTop+"px";
    

    整理一下全部的js代码

    <script>
        //获取元素
            var box = document.getElementById("box");
            //获取显示小图的div
            var small = box.children[0];
            //获取小图中的遮挡的div
            var mask = small.children[1];
            //获取显示大图的div
            var big = box.children[1];
            //获取大div中的大图
            var imgObj = big.children[0];
    
        //显示遮挡层和显示大图的的层
        //鼠标进入事件
        box.onmouseover = function () {
            mask.style.display = "block";
            big.style.display = "block";
        };
        //鼠标离开事件
        box.onmouseout = function () {
            mask.style.display = "none";
            big.style.display = "none";
        };
    
        //为小层注册鼠标移动的事件
        small.onmousemove = function (e) {
            var left = e.clientX - mask.offsetWidth / 2;//横坐标
            var top = e.clientY - mask.offsetHeight / 2;//纵坐标
       //设置遮挡层的left和top
            var x = left - 100;//margin
            var y = top - 100;//margin
    
            x=x<0?0:x;//如果横坐标小于0就设置为0
            y=y<0?0:y;//如果纵坐标小于0就设置为0
            x=x>small.offsetWidth-mask.offsetWidth?small.offsetWidth-mask.offsetWidth:x;
            y=y>small.offsetHeight-mask.offsetHeight?small.offsetHeight-mask.offsetHeight:y;
            
       //设置遮挡层的定位值
            mask.style.left = x + "px";
            mask.style.top = y + "px";
    
       //设置大图的移动距离
            //大图的最大的移动距离
            var imgMaxMove=imgObj.offsetWidth-big.offsetWidth;
            //遮挡层的最大的移动距离
            var maskMaxMove=small.offsetWidth-mask.offsetWidth;
            //大图的横向移动的距离
            var imgMoveLeft=x*imgMaxMove/maskMaxMove;
            //大图的纵向移动的距离
            var imgMoveTop=y*imgMaxMove/maskMaxMove;
    
            //设置大图的left和top---移动的是margin-left和margin-top
    
            imgObj.style.marginLeft=-imgMoveLeft+"px";
            imgObj.style.marginTop=-imgMoveTop+"px";
        };
    </script>
    

    放大镜进阶

    最近要做的这个放大镜的功能需求是这样的
    截取屏幕可视区域的图片然后进行放大。
    为了可以看到动态的效果,所以我在上面加了随机的添加图标的功能,这样就可以看到实时的改变。

    功能分析

    • 设置按钮,点击按钮的时候显示遮挡层和大图框
    • 设置添加图标按钮,点击在屏幕的随机位置生成一个图标
    • 在文本框中输入文字
    • 截取可视区域的屏幕并生成图片
    • 将可视区域的图片进行放大放入到大图框中
    • 鼠标移动的时候大图框中的也同样移动

    效果图

    tb.png

    截屏插件 html2canvas

    html2canvas 官网

    这个插件是让你整体截屏或者部分截屏的功能,截屏直接在浏览器上使用。这个插件是基于dom操作,但是不是百分百准确的,因为它并不是生成一个图片,而是基于页面上的信息截图。(说白了就是截下来一部分的信息然后直接绘制到另一个地方,并不是保存成了图片文件)

    注意事项

    这个插件有一定的限制

    • 第一个就是文档不是很全,过于简单
    • 第二个是其工作原理不是真正生成一个截图,而是遍历所有的dom元素构建页面,所以很多css属性无法使用
    • 第三个是要求图像同源且没有代理,这个脚本不渲染flash\applet\iframe等内容

    可用参数

    这些参考API和中文的简书,写的很清楚

    html2canvas中文简书

    demo

    • 先引入js文件
    <script type="text/javascript" src="html2canvas.js"></script>
    
    • 写html结构
    <body id="bd">
        <div id="view" style="background:url('./test.png') no-repeat;background-size: contain; width: 700px; height: 500px;">
            <input type="button" value="截图" onclick="takeScreenshot()">
        </div>
    </body>
    
    • 写js代码
    <script type="text/javascript">
        function takeScreenshot() {
            html2canvas(document.getElementById('bd'), {
                onrendered: function(canvas) {
                    document.body.appendChild(canvas);
                }
            });
        }
    </script>
    
    

    下面还是回归正题,开始写放大镜的结构:

    放大镜的html结构

    <style>
            *{
                margin:0;
                padding:0;
            }
            body{
                background-image: url('./hua.jpg');
                background-repeat: no-repeat;
                position: absolute;
                width: 100%;
                height: 100%;
            }
            #dv{
                position: absolute;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background-color: rgba(0,0,0,0.5);
                display: none;
            }
    
            #btn{
                position:absolute;
                top: 20px;
                left: 20px;
            }
            
            #mask{
                width: 175px;
                height:175px;
                position: absolute;
                top: 0;
                left: 0;
                background-color: rgba(255,150,0,.5);
                cursor: move;
            }
    
            #look{
                width: 200px;
                height:200px;
                position: absolute;
                top: 30px;
                right: 30px;
                border: 1px solid #f40;
                cursor: move;
                overflow: hidden;
            }
            #box{
                width: 100%;
                height:100%;
            }
    </style>
    
    <body id="bd">
        hello world!!
        <input type="button" value="放大镜" id="btn"/>
        <div id="dv"><!--遮罩层-->
            <div id='box'></div><!--相当于小图-->
            <div id="mask"></div><!--跟着鼠标的层-->
            <div id="look"><!--显示的区域-->
                <div id="move"></div><!--移动的地方-->
            </div>
        </div>
    </body>
    

    使用jquery进行代码实现

    第一步 获取元素

          //获取id
          var btn = $('#btn');
          var dv = $('#dv');
          var box = $('#box');
          var mask = $('#mask');
          var look = $('#look');
          var move = $('#move');
          //定义图片的最大移动距离和跟着鼠标层的最大移动距离的变量
          var imgMaxMove;
          var maskMaxMove;
    

    第二步 注册按钮点击事件

    • 点击按钮的时候显示遮罩层,同时也显示出来随着鼠标移动的框框,显示出来图片显示的位置。
    • 显示遮罩层的时候截图
    • 点击遮罩层的时候遮罩层消失
            //给按钮注册点击事件
            btn.on('click',function(){
                //截屏功能
                takeScreenshot();
                //遮罩层显示
                dv.css('display','block');
            });
    
            //点击屏幕的时候就消除
            dv.on('click',function(){
                $(this).css('display','none');
            })
    

    第三步 截屏功能

    function takeScreenshot() {
         //根据body进行截屏
         html2canvas(bd, {
              allowTaint: true, //允许跨域
              taintTest: false,  //渲染图片不用测试图片
              //渲染图片
              onrendered: function(canvas) {
                   //将canvas标签转化为img标签
                   canvas.id = 'cv';
                   var dataUrl = canvas.toDataURL();
                   var newImg = document.createElement("img");
                   newImg.src = dataUrl;
                   //设置图片的长和宽
                   newImg.width = 4 * bd.width();
                   newImg.height = 4* bd.height();
                   //把图片的长宽赋值给外面的盒子
                   move.width(newImg.width);
                   move.height(newImg.height);
                   //把图片加到盒子上
                   move.append(newImg);
                },
            });
          }
    

    第四步 注册鼠标移动事件

    • 不考虑兼容的问题,使用clientX
    • 确定不要让跟着鼠标的小块出了屏幕,给它设定范围
    • 比例这个东西啊,因为之前截屏的时候,长度就进行了扩大,所以比例也不好掌握,后面自己慢慢的调。。。总会差不多的。(给自己留的bug)
    //给鼠标注册移动事件
    dv.on('mousemove',function(e){
               var left = e.clientX - mask.width() / 2;//横坐标
                var top = e.clientY - mask.height() / 2;//纵坐标
                //设置遮挡层的left和top
                var x = left;
                var y = top;
    
                x=x<0?0:x;//如果横坐标小于0就设置为0
                y=y<0?0:y;//如果纵坐标小于0就设置为0
                x=x>box.width()-mask.width()?box.width()-mask.width():x;
                y=y>box.height()-mask.height()?box.height()-mask.height():y;
    
                //确定跟着鼠标动的小块的定位值
                mask.offset({"left":x,"top":y});
    
                //大图的最大的移动距离
                imgMaxMove=newImg.width-look.width();
                //遮挡层的最大的移动距离
                maskMaxMove=box.width()-mask.width();
                  
                //大图的横向移动的距离
                var imgMoveLeft=x*maskMaxMove/imgMaxMove*9;
                //大图的纵向移动的距离
                var imgMoveTop=y*maskMaxMove/imgMaxMove*9;
                // 给大图设定移动位置
                move.css("marginLeft",-imgMoveLeft);
                move.css("marginTop",-imgMoveTop);
      })
    

    第五步 给屏幕上动态的添加元素

    • 点击添加图标的时候,在屏幕上随机的添加一个图标
    • 可以在文本框中输入文字信息
     $('#jb').on('click',function(){
                var img = document.createElement('img');
                img.src = 'images/jb.jpg';
                img.width = 100;
                img.height = 100;
                var leftRandom = Math.random()*1366; //随机生成横坐标
                var topRandom = Math.random()*768; //随机生成纵坐标
                img.style.position = 'absolute';
                img.style.left = leftRandom + 'px';
                img.style.top = topRandom + 'px';
                $('#show').append(img);
            })
    

    完整代码

    css文件glass.css

    *{
        margin:0;
        padding:0;
    }
    body{
        background-image: url('../images/hua.jpg');
        background-repeat: no-repeat;
        position: absolute;
        width: 100%;
        height: 100%;
    }
    #dv{
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0,0,0,0.5);
        display: none;
    }
    
    #btn{
        position:absolute;
        top: 100px;
        left: 100px;
        width: 100px;
        height:50px;
        background-color:rgba(0,0,0,.9);
        border-radius: 8px;
        line-height: 50px;
        text-align: center;
        color: #fff;
        cursor: pointer;
        font-size: 16px;
    }
    
    #mask{
        width: 200px;
        height:200px;
        position: absolute;
        top: 0;
        left: 0;
        background-color: rgba(255,150,0,.5);
        cursor: move;
    }
    
    #look{
        width: 300px;
        height:300px;
        position: absolute;
        bottom: 30px;
        right: 30px;
        border: 1px solid #f40;
        cursor: move;
        overflow: hidden;
    }
    #box{
        width: 100%;
        height:100%;
    }
    
    #jb{
        position:absolute;
        left: 100px;
        top:200px;
        width: 100px;
        height: 50px;
        background-color: rgba(0,0,0,.9);
        border-radius: 8px;
        line-height: 50px;
        text-align: center;
        color: #fff;
        cursor: pointer;
        font-size: 16px;
    }
    
    #txt{
        position: absolute;
        left: 100px;
        top: 300px;
        width: 100px;
        height: 50px;
    }
    
    

    index.html

    <link rel="stylesheet" href="css/glass.css"/>
    <script type="text/javascript" src="libs/jquery.min.js"></script>
    <script type="text/javascript" src="libs/html2canvas.js"></script>
    <script type="text/javascript" src="js/glass.js"></script>
    
    <body id="bd">
    hello world!!
    <div id="jb">显示图标</div>
    <input type="text" id="txt"/>
    <div id="show"></div>
    <div id='btn'>放大镜</div>
    <div id="dv"><!--遮罩层-->
        <div id='box'></div><!--相当于小图-->
        <div id="mask"></div><!--跟着鼠标的区域-->
        <div id="look">
            <div id="move"></div><!--移动的地方-->
        </div><!--显示的区域-->
    </div>
    
    <script>
        $(function(){
            $('#dv').glass();
    
            $('#jb').on('click',function(){
                var img = document.createElement('img');
                img.src = 'images/jb.jpg';
                img.width = 100;
                img.height = 100;
                var leftRandom = Math.random()*1366;
                var topRandom = Math.random()*768;
                img.style.position = 'absolute';
                img.style.left = leftRandom + 'px';
                img.style.top = topRandom + 'px';
                $('#show').append(img);
    
            })
        });
    </script>
    </body>
    

    js文件 glass.js

    
    (function($){
        $.fn.glass = function(){
            var mask = $('#mask');
            var box = $('#box');
            var look = $('#look');
            var move = $('#move');
            var btn = $('#btn');
            var imgMaxMove;
            var maskMaxMove;
            var _this = $(this);
    
            //点击按钮
            btn.on('click',function(){
                move.html('');
                takeScreenshot();
                _this.css('display','block');
            });
    
            //点击屏幕的时候就消除
            _this.on('click',function(){
                _this.css('display','none');
            })
    
    
            //获取屏幕截图
            function takeScreenshot() {
                alert('1');
                html2canvas($('#bd'), {
                    allowTaint: true,
                    taintTest: false,
                    onrendered: function(canvas) {
                        canvas.id = 'cv';
                        var dataUrl = canvas.toDataURL();
                        var newImg = document.createElement("img");
                        newImg.src = dataUrl;
                        newImg.width = 4 * $('#bd').width();
                        newImg.height = 4* $('#bd').height();
                        move.width(newImg.width);
                        move.height(newImg.height);
                        move.append(newImg);
    
    
                        _this.on('mousemove',function(e){
                            var left = e.clientX - mask.width() / 2;//横坐标
                            var top = e.clientY - mask.height() / 2;//纵坐标
                            //console.log(mask.width());
                            //设置遮挡层的left和top
                            var x = left;//margin
                            var y = top;//margin
                            x=x<0?0:x;//如果横坐标小于0就设置为0
                            y=y<0?0:y;//如果纵坐标小于0就设置为0
                            x=x>box.width()-mask.width()?box.width()-mask.width():x;
                            y=y>box.height()-mask.height()?box.height()-mask.height():y;
                            mask.offset({"left":x,"top":y});
    
    
                            //大图的最大的移动距离
                            imgMaxMove=newImg.width-look.width();
                            console.log(imgMaxMove);
                            //遮挡层的最大的移动距离
                            maskMaxMove=box.width()-mask.width();
                            console.log(maskMaxMove);
    
                            //大图的横向移动的距离
                            var imgMoveLeft=x*maskMaxMove/imgMaxMove*9;
                            //大图的纵向移动的距离
                            var imgMoveTop=y*maskMaxMove/imgMaxMove*9;
                            move.css("marginLeft",-imgMoveLeft);
                            move.css("marginTop",-imgMoveTop);
                        })
                    },
                });
            }
        }
    })(jQuery);
    
    

    补充

    关于图片的比例问题
    也可以这样做:
    大图的宽 / 小图的宽 = 大图的移动距离 / 小图的移动距离
    这样就将id = move的标签进行设置

    css:
    #move{ position:absolute; top:0; left: 0; }

    js:
    x = newImg.width / $('#bd').width() * x / 2; y = newImg.width / $('#bd').width() * y / 2; $('#move').css('left',-x); $('#move').css('top',-y);

    还是那句话,比例自己调正。。。

    相关文章

      网友评论

      本文标题:javascript实现放大镜插件【含进阶】

      本文链接:https://www.haomeiwen.com/subject/wtqxhxtx.html