超简易图片放大镜

·  阅读 2823
超简易图片放大镜

大家好,我是 Steven。

今集会介绍一个在商城网站经常看到的功能,图片放大镜的效果:

我们试试用最少的 JavaScript,尽量使用 CSS 以及最简单的 HTML 结构去实现,那我们就开始啦。

这个教程的视频版本在 www.bilibili.com/video/BV12N… ,欢迎三连关注!

HTML 的部份

打开 CodePen 编辑器,在 HTML 的部份加入一个 <div>id 名为 image

CSS 的部份

去到 CSS 的部份,新增 #image 选择器,宽度和高度设定为 300px,背景颜色设定为黑色。

然后将需要显示的图片,通过 background-image 设定为背景图片,由于我们要做放大镜的效果,所以这张图片的大小需要大于容器的大小,例如放大镜会将图片放大 3 倍,那图片的大小就是 900px 乘以 900px 了。

然后再通过 background-size,将它设定回 300px 乘以 300px 的大小,而 background-repeat 设定为 no-repeat

再加入 body 选择器,使用 Flexbox 的方式将内容上下左右置中。

JavaScript 的部份

好了,那么如何做到当游标移到图片上时,将图片放大呢?这里涉及到三个 JavaScript Event。在 JavaScript 的部份,加入三个事件监听器:

  • 第一个,是 mouseenter,会在游标进入图片时触发,事件处理函式命名为 enterHandler
  • 第二个,是 mousemove,会在游标在图片上移动时触发,事件处理函式命名为 moveHandler
  • 第三个,是 mouseleave,会在游标离开图片时触发,事件处理函式命名为 leaveHandler

好,那么先处理游标进入图片时放大,离开图片时缩小到原来大小的效果。这个就很简单,平时我们惯用的方法是进入图片时加个 class,离开图片时就移除那个 class。但我想再纯粹一点,今次就用另一个方式试试。

enterHandler 函式内,加入 e.target.setAttribute(),将 zoomed 设定为 1,这样就即是在 <div> 上加入 zoomed="1" 这个属性。

然后在 leaveHandler 函式内,加入 e.target.removeAttribute(),将 zoomed 属性移除。

实现放大缩小功能

回到 CSS 的部份,加入 #image[zoomed] 选择器,代表当 #imagezoomed 这个属性的时候,将 background-size 设定为 3 倍大小,宽度与高度是 900px

测试一下,现在移到图片上就放大,离开图片就回到原来的大小:

再来处理游标移动的情况,回到 JavaScript 的部份,在 moveHandler 函式内定义两个变量,分别是 xy。我想计算出游标移到图片上的 x 方向百份比和 y 方向百份比,位移的数字可以通过 offsetXoffsetY 获取,再除以容器的宽度和高度就可以了。

为了准确获取容器的大小,再定义一个变量 rect,赋值为 e.target.getBoundingClientRect(),然后 x 等于 e.offsetX 除以 rect.widthy 等于 e.offsetY 除以 rect.height,再通过 e.target.style.setProperty 分别将 xy 设定为 CSS 的变量,这样就可以在 CSS 中获取到 xy 的值。

现在可以通过开发者工具,看到 CSS 变量的值:

有了这两个数据,再加多一行 CSS,就可以完成放大镜的效果。你猜到我会怎样做吗?如果有兴趣的话,不妨自己试一试,然后再回来继续看。

回到 CSS 的部份,在 #image[zoomed] 的选择器内加入 background-position 控制背景图片的位置:

  • X 的值设定为 var(--x) 乘以 100%,外层套上 calc()
  • Y 的值设定为 var(--y) 乘以 100%,外层套上 calc()

测试一下,放大镜效果就完成了:

不过,我们还要照顾一下手机版的情况,在手机上,以上的 mouse 事件都不太适用。这个时候就需要监听 touch 事件,分别是 touchstarttouchmovetouchend。刚好可以与 mouse 那三个事件一一对应,先新增它们的事件监听器。

然后主要需要调整的是 moveHandler,因为 touch 事件的 event 物件并没有 offsetXoffsetY,所以我们需要自行计算。

定义两个变量,offsetXoffsetY,判断 e.type 是否为 touchstarttouchmovetouchend

先设定 else 用游标的情况,将 offsetXoffsetY 赋值为 Event 物件内的对应值就可以了。

touch 的情况,首先 touch 是支援多点触碰的,假设我们用一只手指触碰荧幕,要获取第一个触碰点,可以通过 e.touches[0],然后 .pageX 减去 rect.left,这个就是 offsetX 的设定值。运用相同的原理,计算 offsetY 的值。

然后将 xe.offsetX 改为变量 offsetXye.offsetY 改为变量 offsetY,在手机操作的情况下,还要加入 e.preventDefault,这样才可以避免手指在图片上滑动的时候触发页面的卷动。

最后,再来一点优化,当我手指开始点下去的时候,如果不移动的话,放大的就是上一次 xy 的位置,而不是我直接点下去的位置。

mouse 事件没有这个问题的,因为游标要移到图片的哪一个点都好,都一定要有移动的动作,一定会触发到 mousemove,而更正这个情况就很简单,只需要在 enterHandlerleaveHandler 函式内都执行一次 moveHandler 就可以了,注意要将 e 这个参数传递进去。

我们来看看这个案例的完成效果

以上,就是今集要介绍的全部内容。


这个案例的源代码在 codepen.io/stevenlei/p…

你的支持是我的动力,请关注 CodingStartup 起码课,我们一起加油!

分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改