前言:

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

        本篇文章为您分析一下原生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. NKOJ 7.7练习题A IP地址

    问题描述 可以用一个网络地址和一个子网掩码描述一个子网(即连续的 IP 地址范围).其中子网掩码包含 32 个二进制位,前 32-n 位为 1,后 n 位为 0,网络地址的前 32-n 位任意,后 n ...

  2. Docker的MySQL镜像, 实行数据,配置信息,日志持久化

    Docker的MySQL8镜像, 实行数据持久化 使用Docker的MySQL8.0.17实例化一个容器之后需要对其进行数据持久化操作, 使用 docker docker run -p 7797:33 ...

  3. 1047 Student List for Course (25分)

    Zhejiang University has 40,000 students and provides 2,500 courses. Now given the registered course ...

  4. Android 图片裁剪库 uCrop

    引语 晚上好,我是猫咪,我的公众号「程序媛猫咪」会推荐 GitHub 上好玩的项目,挖掘开源的价值,欢迎关注我. 现在 Android 开发,离不开图片,必然也需要图片裁剪功能,这个实现可以调用系统的 ...

  5. 使用webview查找元素,appium查找web页面元素

    9 webview查找元素 9.1 webview 简介 WebView是android中一个非常重要的控件,它的作用是用来展示一个web页面.它使用的内核是webkit引擎,4.4版本之后,直接使用 ...

  6. c++用递归法将一个整数n转换成字符串

    任务描述 用递归法将一个整数n转换成字符串.例如,输入483,应输出字符串“483”.n的位数不确定,可以是任意位数的整数. 测试输入: 预期输出: 程序源码: #include <stdio. ...

  7. 最全的中文NLP资源库,你确定不来看一下吗?

    最全的中文NLP资源库,你确定不来看一下吗? 22/100 发布文章 qq_39248703 hello,小伙伴们大家好,今天给大家分享NLP资源库,可以说是最全的资源库了,很多包非常有趣,值得收藏, ...

  8. pgsql中json格式数组查询结果变成了字符串

    场景复原 最近使用到了json的数组,用来存储多个文件的值,发现在连表查询的时候返回结果变成了字符串. { "id": "repl-placeholder-007&quo ...

  9. python基础:如何使用python pandas将DataFrame转换为dict

    之前在知乎上看到有网友提问,如何将DataFrame转换为dict,专门研究了一下,pandas在0.21.0版本中是提供了这个方法的.下面一起学习一下,通过调用help方法,该方法只需传入一个参数, ...

  10. Cobalt Strike系列教程第六章:安装扩展

    Cobalt Strike系列教程分享如约而至,新关注的小伙伴可以先回顾一下前面的内容: Cobalt Strike系列教程第一章:简介与安装 Cobalt Strike系列教程第二章:Beacon详 ...