前言:

        本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽。

        本篇文章为您分析一下原生JS写淘宝放大镜效果

基本功能:

  • 运用比例来控制移动放大镜从而选择需要放大的区域。

  • 可以根据用户配置来调整放大镜尺寸。

需求分析:

准备两张图片一张小图,一张大图(比例请参考京东或者淘宝页面上的放大镜;本文采用的是350px和800px的)

HTML结构:

    <div class="small">    <!--小图-->
        <div class="move" style="height: 150px; width:150px"></div><!--可以移动的区域-->
    </div>
    <div class="big"></div><!--要显示的大图-->

<div class="move" style="height: 150px; width:150px"></div>

此处的内联样式在后面是需要用js生成,暂时为了看到效果写在这儿了

CSS样式:

    <div class="small">
        <div class="move"></div>
    </div>
    <div class="big"></div>

效果如下:

  

至此,页面基本结构已经完成,下面开始写JS

JS行为:

  1. 由于此处的JS变量不需要供外部使用所以我们直接用一个立即执行函数来完成。

  2. 首先要想到的,放大镜需要用到什么配置(即用户需要更改那些参数才能使用)

    • 小图的url,大图的url
    • 小图和大图要渲染到哪个元素上?
    • 配置小图的宽高
    • 配置大的div宽高
    • 配置大图的宽高
    /**
     * 第一步: 配置(此处配置均可更改)
     */
    var config = {
        smallBg: "images/mouse.jpg",  // 小图背景路径
        bigBg: "images/mouseBigSize.jpg",  // 大图背景路径
        divBig: document.querySelector(".big"),  // 大图div dom元素
        divSmall: document.querySelector(".small"),  // 小图div dom元素
        divMove: document.querySelector(".small .move"),  // 可移动的div元素
        smallImgSize: {  // 小图尺寸
            width: 400,
            height: 400
        },
        divBigSize: {  // 大的div尺寸
            width: 400,
            height: 400
        },
        bigImgSize: {  // 大图尺寸
            width: 800,
            height: 800
        }
    };
配置有了,接下来我们要进行页面的渲染了。此时看看页面,发现页面是这样的

  

空荡荡的,咋整呢?那么接下来我们就让他有图片吧。
    initDivBg();  // 调用函数
    /**
     * 第二步: 初始化div背景
     */
    function initDivBg() {
        // 设置小div的背景                   使用es6的模板字符串拼接
        config.divSmall.style.background = `url("${config.smallBg}") no-repeat left top/100% 100%`;
        // 设置大div的初始背景               使用es6的模板字符串拼接
        config.divBig.style.background = `url("${config.bigBg}") no-repeat`;
    }
整完 他是这样的,是不是感觉么么哒?基本效果都出来?欧力给?

  

接着我们做什么?你把鼠标放上去他会动吗?那个会动的div尺寸我们还没整呢?对吧?你现在看到那个是我们设置了内联式。我们把那个删除看看。他就变成这样了。

  

这不行啊?咋能说跟人跑就跑的?来。下面就是要来计算可移动div的宽高。
因为他的尺寸是可以根据用户更改参数而动态改变的,那他的div宽高要怎么算呢?懵逼了。。。下面来看张分析图

  

假设分析图您看明白了,那么下面的代码你也会敲了吧!giao!!!
    // 第三步: 计算可移动的div的宽高
    config.moveSize = {
        width: config.divBigSize.width / config.bigImgSize.width * config.smallImgSize.width,
        height: config.divBigSize.height / config.bigImgSize.height * config.smallImgSize.height
    }
为啥要这样写,而不是直接添加到配置参数里面?因为他的尺寸是可以根据用户更改参数而动态改变的*3!!!重要的事情1遍就好!
有了宽高,还等啥呢?直接设置就完儿了。
    function initMoveDiv() {
        config.divMove.style.width = config.moveSize.width + "px";
        config.divMove.style.height = config.moveSize.height + "px";
    }
别忘了调用initMoveDiv函数。

  

这可还看的下去,下步干嘛?那当然是想动起来了。
一开始大图div是看不见的,display为none,可移动div也是看不见的,display也为none自行设置吧。

  

当鼠标移入显示大图div和可移动div
那么为谁注册事件呢?(假装看不见-----------小的div)如下:
    /**
     * 第四步:初始化小的div事件
     */
    function initDivSmallEvent() {
        // 鼠标移入事件
        config.divSmall.onmouseenter = function () {
            config.divMove.style.display = "block";  // 可移动div显示
            config.divBig.style.display = "block";   // 大的div显示
        }
        // 鼠标移出事件
        config.divSmall.onmouseleave = function () {
            config.divMove.style.display = "none";  // 可移动div隐藏
            config.divBig.style.display = "none";   // 大的div隐藏
        }
    }
别忘了调用initDivSmallEvent函数。
图有了,框有了,可是他还不会动呢,要可以蹦沙卡拉卡那就完美了。揍~你。下面让他摇摆一下。
但是这怎么摇和怎么摆他可有思绪?
再为他添加一个移动事件就成。

        // 鼠标移动事件
        config.divSmall.onmousemove = function (e) {
            // 把事件e传入getOffset函数中获取鼠标移动的距离。
            var offset = getOffset(e);
            console.log(offset);
        }
为次,我们专门写一个获取鼠标移动的距离的函数。

        /**
         * 第五步: 根据鼠标事件参数,得到鼠标在divsmall中的坐标
         * @param {MouseEvent} e
         */
        function getOffset(e) {
            console.log(e.offsetX)
            // 如果事件源是config.divSmall
            if (e.target === config.divSmall) {
                // 直接返回
                return {
                    x: e.offsetX,
                    y: e.offsetY
                }

            } else {
                // 事件源是divMove,我们就要添加上他的left值,left怎么获的
                var style = getComputedStyle(config.divMove); // 得到divMove最终样式
                var left = parseFloat(style.left);            // 取到他的left值 为啥要用parseFloat因为我们要的是Number,不是string,不用你试着打印出来是带px的。
                var top = parseFloat(style.top);              // 取到他的top值
                return {
                    // 这里的加1是border的宽度,可以加可以不加。精确写。
                    x: e.offsetX + left + 1,                  // 返回时加上left值
                    y: e.offsetY + top + 1                    // 返回时加上top值
                }
            }
        }

看看效果
可能到这儿您有些么么哒。没关系,请往下看看分析图

  

来来先瞅瞅这儿,这儿瞅明白儿再写上面那函数。
两张图够了吧,不够也没了。

  

  

既然我们已经得到了他的运动轨迹,那么
下面就是让这个该死的div动起来,EV8D。
让他随鼠标的移动而改变可移动div的left,top值。
上代码;

        config.divSmall.onmousemove = function (e) {
            var offset = getOffset(e);
            setPosition(offset);  // 调用函数
        }

        /**
         * 第六步: 根据鼠标坐标,设置divMove的坐标
         * @param {*} offset
         */
        function setPosition(offset) {
            // 设置可移动div的left值;   config.moveSize.width / 2; 可移动div的一半,为啥这样做。让你的十字架始终在可以移动div的中间(瞄的比较准)
            var left = offset.x - config.moveSize.width / 2;
            // 设置可移动div的top值
            var top = offset.y - config.moveSize.width / 2;
            // 判断边界
            if (left < 0) {
                left = 0;
            }
            if (top < 0) {
                top = 0;
            }
            if (left > config.smallImgSize.width - config.moveSize.width) {
                left = config.smallImgSize.width - config.moveSize.width
            }
            if (top > config.smallImgSize.height - config.moveSize.height) {
                top = config.smallImgSize.height - config.moveSize.height
            }
            // 重新设置可移动div的left和top值
            config.divMove.style.left = left + "px";
            config.divMove.style.top = top + "px";
        }
效果如下图:

  

心情澎湃,最后一步。就收工了。
熬出头了???
设置大图的的背景图位置?
但是要如何设置呢?同样的需要计算比例
先分析一下:看下图

  

因此,我们要先获得可移动div的最终left和top值。
看明白了上代码:
        config.divSmall.onmousemove = function (e) {
            var offset = getOffset(e);
            setPosition(offset);
            setBigBgPosition(); //调用函数
        }
        /**
         * 最后一步: 设置大图背景图位置
         */
        function setBigBgPosition() {
            var style = getComputedStyle(config.divMove);  // 得到divMove最终样式
            var left = parseFloat(style.left);  // 取到他的left值
            var top = parseFloat(style.top);    // 取到他的top值
            var bgLeft = left / config.smallImgSize.width * config.bigImgSize.width;  // 看分析图
            var bgTop = top / config.smallImgSize.height * config.bigImgSize.height;  // 看分析图
            config.divBig.style.backgroundPosition = `-${bgLeft}px -${bgTop}px`;      // 设置背景图。
        }
至此,我们把淘宝放大镜效果做完了,代码肯定多多少少有些不完整,还有待优化,但是我尽力啦。后面再慢慢补上吧。阿里阿朵。
让我们看看完整的效果。

  !

下面附上完整代码:
HTML部分:
    <div class="small">
        <div class="move"></div>
    </div>
    <div class="big"></div>

    <script src="./index.js"></script>

CSS部分:

        .small {
            position: relative;
            width: 350px;
            height: 350px;
            border: 1px solid #cccccc;
            float: left;
            background-clip: padding-box;
        }
        .big{
            display: none;
            width: 350px;
            height: 350px;
            border: 1px solid #cccccc;
            float: left;
            margin-left: 10px;
            background-clip: padding-box;
        }
        .small .move{
            display: none;
            position: absolute;
            left: 0;
            top: 0;
            background: rgba(255, 255, 0, .2);
            border: 1px solid #cccccc;
            box-sizing: border-box;
            cursor: move;
        }

JS部分:

/**
 * 初始化
 */
(function () {
    /**
     * 第一步: 配置
     */
    var config = {
        smallBg: "images/mouse.jpg",  // 小图背景路径
        bigBg: "images/mouseBigSize.jpg",  // 大图背景路径
        divBig: document.querySelector(".big"),  // 大图div dom元素
        divSmall: document.querySelector(".small"),  // 小图div dom元素
        divMove: document.querySelector(".small .move"),  // 可移动的div元素
        smallImgSize: {  // 小图尺寸
            width: 350,
            height: 350
        },
        divBigSize: {  // 大的div尺寸
            width: 350,
            height: 350
        },
        bigImgSize: {  // 大图尺寸
            width: 800,
            height: 800
        }
    };
    // 第二步: 计算可移动的div的宽高
    config.moveSize = {
        width: config.divBigSize.width / config.bigImgSize.width * config.smallImgSize.width,
        height: config.divBigSize.height / config.bigImgSize.height * config.smallImgSize.height
    }
    console.log(config)
    initDivBg();
    initMoveDiv();
    initDivSmallEvent();

    /**
     * 初始化div背景
     */
    function initDivBg() {
        config.divSmall.style.background = `url("${config.smallBg}") no-repeat left top/100% 100%`;
        config.divBig.style.background = `url("${config.bigBg}") no-repeat`;
    }
    /**
     * 第三步: 初始化可移动的div
     */
    function initMoveDiv() {
        config.divMove.style.width = config.moveSize.width + "px";
        config.divMove.style.height = config.moveSize.height + "px";
    }
    /**
     * 初始化小图div的鼠标事件
     */
    function initDivSmallEvent() {
        config.divSmall.onmouseenter = function () {
            config.divMove.style.display = "block";
            config.divBig.style.display = "block";
        }
        config.divSmall.onmouseleave = function () {
            config.divMove.style.display = "none";
            config.divBig.style.display = "none";
        }
        config.divSmall.onmousemove = function (e) {
            var offset = getOffset(e);
            setPosition(offset);
            setBigBgPosition();
        }
        /**
         * 最后一步: 设置大图背景图位置
         */
        function setBigBgPosition() {
            var style = getComputedStyle(config.divMove);
            var left = parseFloat(style.left);
            console.log(left)
            var top = parseFloat(style.top);
            var bgLeft = left / config.smallImgSize.width * config.bigImgSize.width;
            var bgTop = top / config.smallImgSize.height * config.bigImgSize.height;
            config.divBig.style.backgroundPosition = `-${bgLeft}px -${bgTop}px`;
            console.log(bgLeft)
        }

        /**
         * 第六步: 根据鼠标坐标,设置divMove的坐标
         * @param {*} offset
         */
        function setPosition(offset) {
            // 设置可移动div的left值;   config.moveSize.width / 2; 可移动div的一半,为啥这样做。让你的十字架始终在可以移动div的中间(瞄的比较准)
            var left = offset.x - config.moveSize.width / 2;
            // 设置可移动div的top值
            var top = offset.y - config.moveSize.width / 2;
            // 判断边界
            if (left < 0) {
                left = 0;
            }
            if (top < 0) {
                top = 0;
            }
            if (left > config.smallImgSize.width - config.moveSize.width) {
                left = config.smallImgSize.width - config.moveSize.width
            }
            if (top > config.smallImgSize.height - config.moveSize.height) {
                top = config.smallImgSize.height - config.moveSize.height
            }
            // 重新设置可移动div的left和top值
            config.divMove.style.left = left + "px";
            config.divMove.style.top = top + "px";
        }
        /**
         * 根据鼠标事件参数,得到鼠标在divsmall中的坐标
         * @param {MouseEvent} e
         */
        function getOffset(e) {
            if (e.target === config.divSmall) {
                return {
                    x: e.offsetX,
                    y: e.offsetY
                }
            } else {
                // 事件源是divMove
                var style = getComputedStyle(config.divMove);
                var left = parseFloat(style.left);
                var top = parseFloat(style.top);
                return {
                    x: e.offsetX + left + 1,
                    y: e.offsetY + top + 1
                }
            }
        }
    }
}())

结语

整完!

js 实现淘宝放大镜功能,可更改配置参数 带完整版解析代码[magnifier.js]的更多相关文章

  1. js 实现淘宝无缝轮播图效果,可更改配置参数 带完整版解析代码[slider.js]

    前言:         本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽.         本篇文章为您分析一下原生JS写淘宝无缝轮播图效果 需求分析: ...

  2. js 实现图片瀑布流效果,可更改配置参数 带完整版解析代码[waterFall.js]

    前言:         本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽.         本篇文章为您分析一下原生JS实现图片瀑布流效果 页面需求 1 ...

  3. js 实现文字滚动功能,可更改配置参数 带完整版解析代码。

    前言:         本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽.         本篇文章为您分析一下原生JS写文字滚动效果 需求分析: 需要 ...

  4. js 实现对象的混合与克隆效果,带完整版解析代码[helpers.js]

    前言:         本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽.         本篇文章为您分析一下原生JS写淘宝无缝轮播图效果 对象混合 ...

  5. JS仿淘宝详情页菜单条智能定位效果

    类似于淘宝详情页菜单条智能定位 对于每个人来说并不陌生!如下截图所示:红色框的那部分! 基本原理: 是用JS侦听滚动事件,当页面的滚动距离(页面滚动的高度)大于或者等于 "对象"( ...

  6. vue实现淘宝购物车功能

    淘宝购物车功能,效果如下图 非常简单的逻辑,没有做代码的封装,代码如下 <div class="list-container"> <div class=" ...

  7. js实现百度,淘宝搜索功能

        Common.js //封装类名 function byClassName(sClassName){ if(document.getElementsBYClassName){ return d ...

  8. javascript项目实战之原生js模拟淘宝购物车

    通过JavaScript实现类似与淘宝的购物车效果,包括商品的单选.全选.删除.修改数量.价格计算.数目计算.预览等功能的实现.实现的效果图: 相应的代码: shoppingCart.html < ...

  9. 模仿淘宝首页写的高仿页面,脚本全用的原生JS,菜鸟一枚高手看了勿喷哈

    自己仿照淘宝首页写的页面,仿真度自己感觉可以.JS脚本全是用原生JavaScript写得,没用框架.高手看了勿喷,请多多指正哈!先上网页截图看看效果,然后上源码: 上源码,先JavaScript : ...

随机推荐

  1. IOS部分APP使用burpsuite抓不到包原因

    曾经在ios12的时候,iphone通过安装burpsuite的ca证书并开启授权,还可以抓到包,升级到ios13后部分app又回到以前连上代理就断网的情况. 分析:ios(13)+burpsuite ...

  2. 基于华为云IoT Studio自助生成10万行代码的奥秘

    华为IoT小助手们搬好板凳.备好笔记本.听了HDC.Cloud的几场华为云技术架构师的直播讲课,感觉获益匪浅却又似懂非懂,直后悔自己没有好好打下基础.为了避免再次出现这样的情况,小助手偷偷跑去找了华为 ...

  3. 剖析手写Vue,你也可以手写一个MVVM框架

    剖析手写Vue,你也可以手写一个MVVM框架# 邮箱:563995050@qq.com github: https://github.com/xiaoqiuxiong 作者:肖秋雄(eddy) 温馨提 ...

  4. 面试官: 说说你对async的理解

    大家好,我是小雨小雨,致力于分享有趣的.实用的技术文章. 内容分为翻译和原创,如果有问题,欢迎随时评论或私信,希望和大家一起进步. 分享不易,希望能够得到大家的支持和关注. TL;DR async是g ...

  5. PHP中涉及文件路径的讨论

    #1 $_SERVER中的PHP_SELF,当前执行脚本的文件名,与 document root 有关.例如,在地址为 http://example.com/test.php/foo.bar 的脚本中 ...

  6. Genetic CNN: 经典NAS算法,遗传算法的标准套用 | ICCV 2017

    论文将标准的遗传算法应用到神经网络结构搜索中,首先对网络进行编码表示,然后进行遗传操作,整体方法十分简洁,搜索空间设计的十分简单,基本相当于只搜索节点间的连接方式,但是效果还是挺不错的,十分值得学习 ...

  7. c++类模板之分文件编写问题及解决

    我们在实际项目中一般习惯头文件(.h)和源文件(.cpp)分开写,这样做的好处良多,但是如果遇到了类模板,这样可能会有一点儿问题. 我们通过一个例子来看: person.h: #pragma once ...

  8. 06-jmeter参数化(函数对话框使用)

    概念: 1.变量命名的规则:字母.下划线开头,可包含数字,严格区分大小写 2.配置元件:用户定义的变量-------值是不变化的 用户命名的参数--------可以动态获取的并传参的 jmeter函数 ...

  9. Java日志管理:Logger.getLogger()和LogFactory.getLog()的区别(详解Log4j)

    Java日志管理:Logger.getLogger()和LogFactory.getLog()的区别(详解Log4j) 博客分类: Java综合   第一.Logger.getLogger()和Log ...

  10. 常见的 PHP 面试题和答案分享

    如何直接将输出显示给浏览器? 将输出直接显示给浏览器,我们必须使用特殊标记 <?=and?>. PHP 是否支持多重继承? PHP 只支持单继承.PHP 的类使用关键字 extends 继 ...