今天会介绍一个在商城网站经常看到的功能,图片放大镜的效果:
我们试试用最少的 JavaScript,尽量使用 CSS 以及最简单的 HTML 结构去实现,那我们就开始啦。
如果不会没关系可以找我拿相关资料教程 点击 这里即可领取资料,让我们一起学习吧
HTML 的部份 打开 CodePen 编辑器,在 HTML 的部份加入一个
,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,这样就即是在
上加入 zoomed="1" 这个属性。 然后在 leaveHandler 函式内,加入 e.target.removeAttribute(),将 zoomed 属性移除。
实现放大缩小功能 回到 CSS 的部份,加入 #image[zoomed] 选择器,代表当 #image 有 zoomed 这个属性的时候,将 background-size 设定为 3 倍大小,宽度与高度是 900px。
测试一下,现在移到图片上就放大,离开图片就回到原来的大小:
再来处理游标移动的情况,回到 JavaScript 的部份,在 moveHandler 函式内定义两个变量,分别是 x 和 y。我想计算出游标移到图片上的 x 方向百份比和 y 方向百份比,位移的数字可以通过 offsetX 和 offsetY 获取,再除以容器的宽度和高度就可以了。 为了准确获取容器的大小,再定义一个变量 rect,赋值为 e.target.getBoundingClientRect(),然后 x 等于 e.offsetX 除以 rect.width,y 等于 e.offsetY 除以 rect.height,再通过 e.target.style.setProperty 分别将 x 和 y 设定为 CSS 的变量,这样就可以在 CSS 中获取到 x 和 y 的值。
现在可以通过开发者工具,看到 CSS 变量的值:
有了这两个数据,再加多一行 CSS,就可以完成放大镜的效果。你猜到我会怎样做吗?如果有兴趣的话,不妨自己试一试,然后再回来继续看。 回到 CSS 的部份,在 #image[zoomed] 的选择器内加入 background-position 控制背景图片的位置:
X 的值设定为 var(--x) 乘以 100%,外层套上 calc()
Y 的值设定为 var(--y) 乘以 100%,外层套上 calc()
测试一下,放大镜效果就完成了:
不过,我们还要照顾一下手机版的情况,在手机上,以上的 mouse 事件都不太适用。这个时候就需要监听 touch 事件,分别是 touchstart、touchmove 和 touchend。刚好可以与 mouse 那三个事件一一对应,先新增它们的事件监听器。
然后主要需要调整的是 moveHandler,因为 touch 事件的 event 物件并没有 offsetX 和 offsetY,所以我们需要自行计算。 定义两个变量,offsetX 和 offsetY,判断 e.type 是否为 touchstart、touchmove 或 touchend。
先设定 else 用游标的情况,将 offsetX 与 offsetY 赋值为 Event 物件内的对应值就可以了。
而 touch 的情况,首先 touch 是支援多点触碰的,假设我们用一只手指触碰荧幕,要获取第一个触碰点,可以通过 e.touches[0],然后 .pageX 减去 rect.left,这个就是 offsetX 的设定值。运用相同的原理,计算 offsetY 的值。
然后将 x 的 e.offsetX 改为变量 offsetX,y 的 e.offsetY 改为变量 offsetY,在手机操作的情况下,还要加入 e.preventDefault,这样才可以避免手指在图片上滑动的时候触发页面的卷动。
最后,再来一点优化,当我手指开始点下去的时候,如果不移动的话,放大的就是上一次 x 和 y的位置,而不是我直接点下去的位置。 mouse 事件没有这个问题的,因为游标要移到图片的哪一个点都好,都一定要有移动的动作,一定会触发到 mousemove,而更正这个情况就很简单,只需要在 enterHandler 和 leaveHandler 函式内都执行一次 moveHandler 就可以了,注意要将 e 这个参数传递进去。
我们来看看这个案例的完成效果
以上,就是今集要介绍的全部内容。