手牵手,带你用原生js实现放大镜特效(一):

前言:

学习该特效需要掌握client、offset系列的知识,否则会有点混乱,可以看我之前写的文章精讲-offset系列、scroll系列、client系列~,再来学习该文章,这样会好很多哦~

实现原理:

首先布局上,很明显要准备两个基本的容器,一个small,一个big,还要准备两张完全相同的图片,但是尺寸不同,每个容器中放入相应大小的图片,但是小的容器中还要放入一个可以移动的遮罩。其次就是在实现上,可根据以下步骤来一步一步完成。

布局代码:

<div id="box">
    <div id="small">
        <img src="./images/small.png" width="350" alt="">
        <div id="mask"></div>
    </div>
    <div id="big">
        <img src="./images/big.jpg" width="800" alt="">
    </div>
</div>
复制代码

代码的样式最后会贴上,不要着急~

接下来,我们注册鼠标进入事件(在box中即可):

box.onmouseover=function(){
    mask.style.display='block';
    big.style.display='block';
}
复制代码

注册鼠标离开事件:

box.onmouseout=function(){
    mask.style.display='none';
    big.style.display='none';
}

复制代码

再接下来,就是重难点了,需要好好理解与消化~

第一步: 为小的容器注册移动事件,并且让mask随着鼠标的移动而移动:

small.onmousemove=function(e){
    var x = e.clientX;
    var y = e.clientY;
    mask.style.left = x +'px';
    mask.style.top= y +'px';
}
复制代码

效果如下:

问题: 会发现鼠标跟mask并没有连在一起,而是在它的左上方,那是什么原因导致了这个问题呢?

答案:

在给box的样式设置中加了这个margin的属性,所以下面我们要把这个值减掉,此时鼠标就在mask的左上角啦~

small.onmousemove=function(e){
    var x = e.clientX;
    var y = e.clientY;
    x = x - 50;
    y = y - 50;
    mask.style.left = x +'px';
    mask.style.top= y +'px';
}
复制代码

第二步: 让鼠标在mask的中心位置显示:

要想实现该效果,很明显,只需要让mask向左移动自身宽度的1/2,向上移动高度的1/2即可

small.onmousemove=function(e){
    var x = e.clientX-mask.offsetWidth/2;
    var y = e.clientY-mask.offsetHeight/2;
    x = x - 50;
    y = y - 50;
    mask.style.left = x +'px';
    mask.style.top= y +'px';
}
复制代码

到此,会发现一直存在的一个问题:mask可以在页面的任何位置移动,显然这并不符合我们的需求,我们只需要它在small中移动。

第三步: 让mask只在small所在区域移动,不可以在这之外的区域移动

若要实现这样的效果,那必然会有一个移动的最大值,也有一个移动的最小值。当超过这个最大值时,就不可以继续移动了,而是保持这个最大值,若没有超过,就是保留当前这个值,若小于这个最小值,也不可以继续移动了,而是保持这个最小值~

为了大家更直观的理解,下面我画图来为大家解释一下:

small.onmousemove=function(e){
    var x = e.clientX-mask.offsetWidth/2;
    var y = e.clientY-mask.offsetHeight/2;
    x = x - 50;
    y = y - 50;
    
    //最小值
    x = x < 0 ? 0 : x;
    y = y <0 ? 0 : y;
    
    //最大值
    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';
}
复制代码

到此,mask已经不能在small之外的地方移动了,而且鼠标也在mask中心位置~

第四步: mask在small上移动,big上等比例展示相应的部分

若要实现这个效果,则要弄明白一个比例关系式,我先举个例子:

我之所以举这个例子,就是因为small与big之间也存在一个对应的比例关系,这也是放大镜特效实现的最关键的地方。

我们可以知道mask移动的距离与最大距离,也可以知道大图移动的最大距离,只需要求大图移动的距离即可!

比例: mask的移动距离/大图的移动距离=mask的最大移动距离/大图的最大移动距离

所以:大图的移动距离=mask的移动距离*大图的最大移动距离/mask的最大移动距离

以横坐标为例:

  • mask的移动距离 : x
  • 大图的最大移动距离 : big.children[0].offsetWidth - big.offsetWidth
  • mask的最大移动距离 : small.offsetWidth - mask.offsetWidth

所以大图移动的距离就可以算出来了~

以上,第一点mask的移动距离 和第三点mask的最大移动距离上面都解释过了,但是这个大图的最大移动距离可能有些人还不能理解,那我这里来解释一下,大图的容器box的宽度没有大图的宽度大,这样就很好理解了吧~

small.onmousemove=function(e){
    var x = e.clientX-mask.offsetWidth/2;
    var y = e.clientY-mask.offsetHeight/2;
    x = x - 50;
    y = y - 50;
    
    //最小值
    x = x < 0 ? 0 : x;
    y = y <0 ? 0 : y;
    
    //最大值
    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 maskMoveMaxX = small.offsetWidth - mask.offsetWidth;
    var maskMoveMaxY = small.offsetHeight - mask.offsetHeight;
    var bigMoveMaxX = big.children[0].offsetWidth - big.offsetWidth;
    var bigMoveMaxY = big.children[0].offsetHeight - big.offsetHeight;

    var bigImgX = x * bigMoveMaxX / maskMoveMaxX;
    var bigImgY = y * bigMoveMaxY / maskMoveMaxY;
}
复制代码

第五步:将大图移动的距离赋值给负margin:

这里大家可能会有疑惑, (1)为什么是负margin?

大家可以进一些购物网站看一下放大镜的效果,当mask在小图上向右移动时,其实大图是向左移动的,则方向是反的,所以当然是负margin咯~

(2)那为什么要将计算的结果赋值给margin,而不是left,或者top呢?

大家可以先试一下,试一下就知道为什么了。因为我们只是给big设置了定位,它脱离了文档流,但是里面的内容并没有脱离文档流,所以left与top的值不起作用,所以我们用margin.

small.onmousemove=function(e){
    var x = e.clientX-mask.offsetWidth/2;
    var y = e.clientY-mask.offsetHeight/2;
    x = x - 50;
    y = y - 50;
    
    //最小值
    x = x < 0 ? 0 : x;
    y = y <0 ? 0 : y;
    
    //最大值
    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 maskMoveMaxX = small.offsetWidth - mask.offsetWidth;
    var maskMoveMaxY = small.offsetHeight - mask.offsetHeight;
    var bigMoveMaxX = big.children[0].offsetWidth - big.offsetWidth;
    var bigMoveMaxY = big.children[0].offsetHeight - big.offsetHeight;

    var bigImgX = x * bigMoveMaxX / maskMoveMaxX;
    var bigImgY = y * bigMoveMaxY / maskMoveMaxY;
    
    big.children[0].style.marginLeft = -bigImgX +'px';
    big.children[0].style.marginTop = -bigImgY +'px';
}
复制代码

好啦,到这里所有的逻辑代码都结束啦,希望对你有所帮助~

那样式代码我这里就不贴了,大家可以去我的码云上下载下来码云

转载于:https://juejin.im/post/5cfe2e55518825225162cfbd

猜你喜欢

转载自blog.csdn.net/weixin_34408717/article/details/93180651