新葡亰496net Web前端 放大仪器组件

放大仪器组件



图片 1

前言

随手打开一个电商网站(如淘宝),查看商品的时候,
把鼠标放到图片上都可以看到图片的更多细节,像把图片局部放大了一样(效果如下GIF)。这篇文章就是讲述这个放大器的实现。

图片 2

放大器

经常逛某宝可以发现,查看商品时都有如下的放大功能,鼠标放到图片上可以看到图片的细节,那么它是如何实现的呢?是真的将图片放大了吗?这篇文章就是讲述这个放大器是如何实现的。

我们平时在电商网站购物时,需要对选取的某一个商品进行详情查看,此时当鼠标在商品图片上某一部分移动查看时旁边就会出现一个该部分图片的放大效果,这样就能够更好的对商品进行分析,下面就使用原生js来实现一下类似放大镜的效果。

原理

在左边的盒子中放入图片的 缩略图
,右边的盒子只有在鼠标放上去的时候显示,并且放置的是对应图片的大图,这个大图只在右边盒子中显示出局部。

鼠标放在左边缩略图的时候,会显示出一个遮罩层(mask), 这个 mask
覆盖缩略图的位置,会在右边的盒子中“局部放大”显示。更确切的说是只显示右边图片的局部。

图片 3

初始原理图

图中 蓝色区域 代表遮罩层, 绿色方框 代表放大图的原始大小,而 红色方框
就是我们看到的局部放大部分。 注意,这里有个比例显示要求:遮罩层大小 /
缩略图大小 = 放大部分 / 图片原始大小

当鼠标在左边缩略图中移动时,会带着这个遮罩层移动。获取遮罩层(mask)在小图中的位置,然后改变对应大图在右边盒子中局部显示的位置

当遮罩层向下移动的时候,这个大图向上等比例移动,就会显示对应的局部放大区域。只要把溢出的部分隐藏(overflow:hidden)即可达到放大效果。

图片 4

移动mask & 比例显示

图中黑色箭头是一个比例示例: 比如遮罩层mask 100px,
放大显示区域=缩略图显示区域=200px, 原图大小400px (宽高同理)

我前言的时候有说到这个放大器的时候,提到了一个“像”字,为何那么说?

因为这个左边的缩略图片,与右边的图片并非同一张图片。同一张图片放大之后查看局部是会变模糊的,而淘宝等电商网站放大图仍是清晰的,这是因为右边的放大图是左边这个缩略图的高清放大版。你看请求或者在网络状态不佳的情况下加载都可以知道加载了两个不同大小的图。

这样做的目的应该是为了加载网页的时候更快展现商品,而要查看细节的话需要另行加载。

图片 5

思路分析:

实现

我用JS与jquery都实现了一遍,
jquery代码约60行,整体实现还是比较简单的。这里就讲解一下主要代码及思路,具体细节欢迎访问我的GitHub上查看。

html与css部分比较简单,就是有两个小点需要注意,等下说。
(img标签貌似在简书的code中打不出,自行意会正确写法吧)

<div class="box">
    <div class="small">
         <!-- ![](img/123-mini.jpg) -->
          <div class="mask hide"></div>
    </div>
    <div class="big hide">
        ![](img/123-large.jpg)
    </div>
</div>

缩略图的部分 可以使用<img />标签,
也可用background,或者直接引入背景图片。不过要注意这个盒子的大小要由CSS指定,并且要让图片显示完整。我使用background: url("...")来放小图,是因为background-size控制背景图大小比较方便。

而大图部分,最好使用标签展示,这样方便控制
显示出来的位置。使用背景图就要控制background-position,实现起来相对麻烦些(具体实现我还没试过)。

定义类: class="hide" 即默认该元素是隐藏的。用类来体现显示 /
隐藏,方便JS控制样式。

我这里没有写下面的列表部分,因为这个比较简单,而且与放大器功能也无关。

图片 6

1.鼠标切换图片列表时,.pic盒子中的图片相对应切换2.在.pic中生成一个.zoom的盒子,移动该盒子时类似对.pic盒子中的图片进行剪切
2.1 动态获取.zoom盒子相对.pic盒子的background-positin属性值 2.2
对.zoom盒子的移动范围进行限制3.将剪切的图片按比例放大显示到.details的盒子中

css

这部分也比较简单, 简单叙述一下定位和hover效果的问题:

  • 遮罩层和big盒子部分应该设置为 绝对定位 且起始是 隐藏
    的,父元素 相对定位。这样子可以让遮罩层在父元素中移动。
  • 其中 .small.big
    两个对应的元素,要注意图片大小和之前提过的比例显示相符。

遮罩层的显示,我这里参考了 《css secrets》
里面的点阵代码,与淘宝的实现有点不同,先贴代码再说:

.mask { 
    width: 205px;
    height: 205px; 
    /* background-image: url('maskHover.png'); */
    background-image: radial-gradient(rgba(124,165,236, 0.4) 30%, transparent 0),
                    radial-gradient(rgba(124,165,236, 0.4) 30%, transparent 0);
    background-size: 3px 3px;
    background-position: 0 0, 3px 3px;
    position: absolute;
    top: 0;
    left: 0;
    cursor: move; 
}

注释的那行是淘宝的实现方式,比较简单粗暴:引用一张背景图,把我从
background-imagebackground-position 部分的代码都省略了。

授人以鱼不如授人以渔,如何获取这个图片:
随手打开淘宝网站的一个商品页面,然后鼠标放到缩略图上的时候审查元素,会看到一个
span 标签及其css样式,然后就会看到 background: url(...)
,这个url里面 // 代表该url协议与当前网站协议相同,即背景图片网址为:
https://gtms01.alicdn.com/tps/i4/T12pdtXaldXXXXXXXX-2-2.png

打开这个网址的时候是一片黑的,不要紧,下载过来引用进去就是一样的效果了。

图片 7

获取mask背景图

好了,鱼和渔都有了, 下面可以开始JS了。

原理

放大器其实并不是真的将图片放大了。
假如是原图片放大,那么放大后势必会出现一定程度的模糊,而我们平时所看到的,放大后反而更清晰了。
所以这两张图并不相同,一个是缩略图,另一个则是前者的高清放大版
当鼠标放在左侧盒子上时,使遮罩和右侧“放大“图片显示,鼠标移动,带着遮罩随之移动,并使右侧图片等比例进行相应移动,显示出对应的放大后的
局部位置。
当遮罩层向下移动的时候,这个时候大图等比例向上移动,就会显示对应的局部放大区域。然后把溢出的部分隐藏即可达到放大效果。

放大器demo如下:

  • 放大器

注:放大比例 = 左边盒子的大小 /
里面进行剪切的盒子大小,该比例值作为右边盒子显示内容的大小

JS

这里省略 显示 / 隐藏 盒子&mask
的JS内容,直接到渲染遮罩层区域及移动的部分:

先获取遮罩层的左上角的位置,这是为了能够用JS来控制这个盒子的位置然后加到页面中去,这是因为遮罩层的大小已经固定了,只要定好一个点的位置,那么它在缩略图中的区域就是固定下来的。

获取遮罩层左上角坐标的步骤:

  • 获取鼠标在缩略图区域中的坐标(鼠标在浏览器中的位置 –
    盒子距离浏览器顶部的位置): localX & localY
  • 再用 localX & localY , 减去遮罩层的宽高的一半。
    因为我们的遮罩层是跟随鼠标移动的,所以要先获取鼠标的坐标再去计算遮罩层的位置。

    图片 8

    获取mask坐标

let maskX = localX - $(".mask").outerWidth(true) / 2;
let maskY = localY - $(".mask").outerHeight(true) / 2;

然后把遮罩层加到页面上,但在这之前要做一个是否溢出的判断。

即判断我们获取的这个 maskX
的坐标是否在这个盒子里面:如果溢出,就改变左上角的坐标使得盒子与边界部分重叠。这时候就实现:到达边界的时候,鼠标可以在遮罩层的靠近边界区域随意移动而遮罩层不动。
(完成了 遮罩层在缩略图区域中大小不会改变 的需求)

边界处理:

    // 判断mask是否越界, 12个if判断是否左右溢出
    // 34 if判断 是否上下溢出
    if(maskX < 0) {
        maskX = 0;
    }
    if(maskX > $(".small").outerWidth(true) - $(".mask").outerWidth(true)){
        maskX = $(".small").outerWidth(true) - $(".mask").outerWidth(true);
    }
    if(maskY < 0) {
        maskY = 0;
    }
    if(maskY > $(".small").outerHeight(true) - $(".mask").outerHeight(true)){
        maskY = $(".small").outerHeight(true) - $(".mask").outerHeight(true);
    }

// 改变mask的位置, 把遮罩层加到页面上 
$('.mask').css({ 
    left: maskX + "px",  
     top: maskY + "px" 
})

最后也就是最关键的一部分: 等比例移动大图

要先获得这个比例(ratio):大图的宽度 / 缩略图显示的宽度 = 图片移动的距离
/ 遮罩层mask移动的距离

    let ratio = parseInt($(".big img").css("width")) / $(".small").outerWidth(true); 

    // 确定图片移动的距离
    let imgX = ratio * maskX;
    let imgY = ratio * maskY; 

    // 改变图片显示的左上角的位置 来移动图片
    $(".big img").css({
        marginTop: -imgY + "px",
        marginLeft: -imgX + "px"
    })    

获取完整代码请点击文章末尾处链接

顺带一提一个在线工具来调整图片尺寸,这样展示的时候比较方便:美图秀秀网页版

图片 9

调整图片尺寸使用

实现

要实现上面demo中的放大器,首先你得准备两张图,一张正常大小,另一张高清放大版。

html结构比较简单:

<div class="box1">
    <img src="./Images/small.jpg">
    <div class="mask"></div>
</div>
<div class="box2">
    <img src="./Images/big.jpg">
</div>

css部分就不给出了,无非是给盒子设宽高,调一下边距什么的,这里只注意一点:

  • 左侧盒子宽高和右侧一定是成比例的

什么意思呢?
要使放大的区域与左侧遮盖的区域一样,那么左右宽高需要保持相同的比例,相信这一点不难理解。

图片 10

在这里,遮罩宽高为200px,缩略图为400px,显示区域为450px,原图为900px(上图所画原图大小仅做参考)
以宽为例:
遮盖的宽 / 缩略图的宽 = 显示区域的宽 / 原图的宽。
样式设置好了,宽高也就位了,怎么让图片动起来呢?
第一步:先让遮罩动起来
代码如下:

box1.onmousemove = function(event) {
...
var x = event.pageX - box1.offsetLeft - mask.offsetWidth/2;
var y = event.pageY - box1.offsetTop - mask.offsetHeight/2;
...
}


event.pageX减去box1.offsetLeft再减去遮罩的半宽,就得到遮罩的左侧与盒子间的距离,如下图:
(如若对pageX , offsetLeft
等不太清楚,可以参考:JS坐标获取)

图片 11

再对x进行约束,使遮罩无法移出边框,最后将x赋值给left:

...
mask.style.left = x + "px";
mask.style.top = y + "px";
...

这样每次鼠标移动就会更新遮罩的left、top值,使得遮罩移动起来。
第二步:等比例移动右侧大图
先求得小图和大图的比例关系,再乘上x就是大图要移动的距离。

...
var scale = box2.offsetHeight/mask.offsetHeight;
var xx = x*scale;
var yy = y*scale;
img.style.marginLeft = -xx + "px";
img.style.marginTop = -yy + "px";

这样这个放大器就基本实现了,当鼠标移动时,遮罩跟随移动,同时右侧大图等比例移动,达到放大的效果。
最后补充一个在线工具调整图片尺寸,个人觉得比较方便实用。

代码如下

效果展示及源码

预览地址
源码地址

关于

  • 在线工具 —
    美图秀秀网页版
  • demo源码
标签:

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图