前言:

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

        本篇文章为您分析一下原生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. 【cs224w】Lecture 6 - 消息传递 及 节点分类

    目录 Node Classification Probabilistic Relational Classifier Iterative Classification Belief Propagati ...

  2. Java 中的递归

    递归 递归 一种通过调用某个方法来描述需要重复进行的操作.该方法的特点就是可以自己调用自己. 案例一 排队的问题 在生活中,我们经常需要排队.在排队中,我们怎么才能知道自己所排在第几位呢? 我们也许会 ...

  3. Linux 定时实行一次任务命令

    当我们想在指定的时间自动执行 一次 任务的时候,可以使用at命令 启动服务 使用时首先检查atq的服务是否启动 service atd status # 检查atd的状态 service atd st ...

  4. Unity 游戏框架搭建 2019 (二十七、二十八)弃用的代码警告解决&弃用的代码删除

    在前两篇,我们把所有的示例重头到尾整理了一遍. 当前的状态如下: 要做的事情: (完成) 备份:导出文件,并取一个合理的名字. 遗留问题: (完成) 第八个示例与之前的示例代码重复,功能重复. (完成 ...

  5. tornado实现不同app路由分发

    tornado实现app路由分发 from tornado import ioloop from tornado.httpserver import HTTPServer from tornado.w ...

  6. 「一闻秒懂」你了解goroutine和channel吗?

    开源库「go home」聚焦Go语言技术栈与面试题,以协助Gopher登上更大的舞台,欢迎go home~ 背景介绍 大家都知道进程是操作系统资源分配的基本单位,有独立的内存空间,线程可以共享同一个进 ...

  7. [go]map基本使用和底层原理

    1.map基本使用 map声明 var m4 map[int]int //只是声明 没有开辟空间 m4[1]=100 //报错 log.Println(m4) 创建 //1 m3:=make(map[ ...

  8. Python pip高级用法

    1.pip 高级用法为了便于用户安装和管理第三方库和软件,越来越多的编程语言拥有自己的包管理工 具,如 nodejs 的 npm, ruby 的 gem. Python 也不例外,现在 Python ...

  9. Docker之hello world

    Docker Hello World Docker 允许你在容器内运行应用程序, 使用 docker run 命令来在容器内运行一个应用程序. 输出Hello world runoob@runoob: ...

  10. jQuer实时监控input对table进行筛选

    记得以前写过一个预定表格~~~~~比这个更难,一大串前端js~~~忘了~~~好记性不如烂笔头~~记录下,既帮助别人,也帮助自己~~~ 实现思路~通过.on监听input标签的内容变化,通过this获取 ...