JavaScript实现放大镜效果

需求分析

要求做一个如图所示的放大镜,鼠标随动,右键开启关闭,含过渡动画。

大体的思路就是绑定鼠标事件,动态地修改background-position,难点在于background-position的计算要考虑周全。

开关动画部分我们选择用transform: scale来实现,相对于改width / height而言,transform做过渡时可以结合transform-origin解决圆心位移到左上角的问题。

性能优化方面,采用了一个简易节流函数对resize和mousemove事件进行了节流。另外,动态修改CSS时也视情况尽量做到了最简,保证不需要的修改不做。

细节体验方面,因为放大镜元素的cursor设为了none,故选择在放大镜关闭时将元素整体位移至视窗外(第二象限),解决了关闭放大镜后鼠标消失的问题。
在这里插入图片描述

静态CSS部分

首先需要做的是给一个fixed定位,让我们的放大镜脱离文档流,并相对于窗口进行定位。
放大镜有圆形边框,这里用border-radius:50%,并给内外侧都套上box-shadow。
transform: scale需要先给一个初始的0,否则之后在JS中初始化会触发一次动画。
开关时的过渡动画用transition: transform即可。
其他如border,width,height,transform,left,top,background-position等属性则全部通过JS操作。
CSS代码如下:

#magnifier {
   
        position: fixed;
        border-radius: 50%;
        box-shadow: 0 0 4px 2px rgba(51, 51, 51, 0.2) inset,
          0 0 4px 2px rgba(51, 51, 51, 0.3);
        background-image: url("1.jpeg");
        background-repeat: no-repeat;
        transform: scale(0, 0);
        transition: transform 0.15s ease-out;
        cursor: none;
      }

JS部分

持续监听鼠标右键:contextmenu事件,用一个变量控制放大镜的开关,根据该变量的值来决定添加或移除mousemove监听器。

先定义配置项常量,RAD代表放大镜的半径,FPS设置每秒最大的事件触发次数(用于节流),BORDER为放大镜边框的宽度。日后如果要做成组件,这些都可以当做可配置的props传入。

const RAD = 200,
  FPS = 125,
  BORDER = 8;

再定义两个全局变量,toggled记录当前放大镜的开闭状态,mag为放大镜对应的DOM元素。

var toggled = false,
  mag = null;

窗口加载时监听contextmenu,并初始化一些样式。

window.onload = function() {
   
  document.addEventListener("contextmenu", handleRightClick);
  mag = document.getElementById("magnifier");
  Object.assign(mag.style, {
   
    width: `${
     RAD * 2}px`,
    height: `${
     RAD * 2}px`,
    backgroundSize: `${
     window.innerWidth}px ${
     window.innerHeight}px`,
    border: `${
     BORDER}px solid #fff`
  });
};

下面是contextmenu回调的实现。要注意backgroundPosition的值是鼠标坐标取反,并且要把放大镜大小和边框宽度一并计算在内。

function handleRightClick(e) {
   
  e.preventDefault();
  if (toggled) {
   
    // toggle off
    document.removeEventListener("mousemove", handleMouseMove);
    Object.assign(mag.style, {
   
      left: `${
     -RAD * 2}px`,
      top: `${
     
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值