JavaScript初级篇——利用offset系列实现放大镜效果

225 阅读3分钟

一、实现效果

二、功能分析

  • 布局分为小图片盒子、黄色方块(放大镜)、大图片盒子三部分

  • 整个功能实现可分为以下几个步骤:

    1. 鼠标经过小图片盒子后,出现黄色方块并显示大图片盒子,鼠标离开时隐藏
    2. 黄色方块跟随鼠标移动
    3. 大图片跟随黄色方块移动

三、功能实现

3-1、第一步

实现鼠标经过小图片盒子显示黄色方块与大图片盒子,离开时隐藏


  1. 布局预览区域的小图片盒子、黄色方块(放大镜)与大图片盒子和大图片

    • 这三部分使用一个div包裹(预览区域),采用相对定位(方便放大镜与大图片盒子去绝对定位)
    • 大图片盒子起初隐藏,并采用绝对定位定位到合适位置,固定宽高,图片溢出部分隐藏
    • 大图片采用绝对定位,初始top: 0,left:0
    • 黄色方块(放大镜)起初隐藏,采用绝对定位定位到合适位置
<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <style>
      /*预览区域,相对定位,方便大图片盒子去绝对定位*/
      .preview_img {
        position: relative;
        width: 398px;
        height: 398px;
      }
      /*大图片盒子,起初隐藏,采用绝对定位固定到合适位置*/
      .big {
        display: none;
        position: absolute;
        left: 410px;
        top: 0;
        width: 500px;
        height: 500px;
        z-index: 999;
        border: 1px solid #ccc;
        overflow: hidden;/*图片溢出隐藏*/
      }
      /*大图片*/
      .big-img {
        position: absolute;
        top: 0;
        left: 0;
      }
      /*黄色方块放大镜*/
      .mask {
        display: none;
        position: absolute;
        top: 0;
        left: 0;
        width: 300px;
        height: 300px;
        background: #FEDE4F;
        opacity: .5;
        border: 1px solid #ccc;
        cursor: move;
      }

    </style>
  </head>

  <body>
    <!-- 预览区域 -->
    <div class="preview_img">
      <!--小图片-->
      <img src="img/123.jpg" width="398" height="398" alt="">
      <!--黄色方块:放大镜-->
      <div class="mask"></div>
      <!--大盒子与大图片-->
      <div class="big">
        <!--正常场景下此处放分辨率高的大图,这里模拟大图,改变了宽高-->
        <img src="img/123.jpg" width="800" height="800" alt="" class="big-img">
      </div>
    </div>
  </body>
</html>
  1. 为图片预览区域添加鼠标移入移出事件

    • 鼠标移入时展示黄色方块与大图片盒子
    • 鼠标移出时隐藏黄色方块与大图片盒子
const previewImg = document.querySelector('.preview_img');
const mask = document.querySelector('.mask');
const big = document.querySelector('.big');
// 预览区域添加鼠标移入移出事件

// 鼠标移入,显示大图片盒子与黄色方块
previewImg.addEventListener('mouseover', function() {
	mask.style.display = 'block';
	big.style.display = 'block';
})

// 鼠标移出,隐藏大图片盒子与黄色方块
previewImg.addEventListener('mouseout', function() {
	mask.style.display = 'none';
	big.style.display = 'none';
})

3-2、第二步

实现黄色方块跟随鼠标移动

  1. 鼠标要在黄色方块中央,所以:

    • 不能直接将鼠标在小图片盒子内的坐标给黄色方块,这样鼠标会在黄色方块的左上角
    • 所以,获取鼠标在小图片盒子内的坐标后要减去黄色方块自身宽高的一半即为黄色方块的left与top值
  2. 为预览区域添加鼠标移动事件,监听鼠标移动来改变黄色方块的位置

  3. 黄色方块移动时不能超出小图片盒子的范围

    • 如果小于0则设置为0
    • 如果大于最大移动就,则设为最大移动距离(最大移动距离 = 小图片盒子宽度 - 黄色方块宽度

// 放大镜跟随鼠标移动,且不能小于0,不能大于最大移动距离
previewImg.addEventListener('mousemove', function(e) {
  // 获取鼠标在盒子内的坐标
  let mouseX = e.pageX - this.offsetLeft;
  let mouseY = e.pageY - this.offsetTop;

  // 计算放大镜的top 与left,使得鼠标在放大镜中央
  let maskX = mouseX - mask.offsetWidth / 2;
  let maskY = mouseY - mask.offsetHeight / 2;

  // 计算放大镜最大的移动距离
  let maskXMax = this.offsetWidth - mask.offsetWidth;
  let maskYMax = this.offsetHeight - mask.offsetHeight;

  // 最小移动距离不得小于0,最大移动距离不得超过所计算的最大移动距离
  if (maskX <= 0) {
    maskX = 0;
  } else if (maskX >= maskXMax) {
    maskX = maskXMax;
  }
  if (maskY <= 0) {
    maskY = 0;
  } else if (maskY >= maskYMax) {
    maskY = maskYMax;
  }

  // 为放大镜的left top赋值,实现移动
  mask.style.left = maskX + 'px';
  mask.style.top = maskY + 'px';
})

3-3、第三步

实现大图片跟随黄色方块移动

原理:

previewImg.addEventListener('mousemove', function(e) {
  /*
   .......省略上部分代码
  */
  // 大图移动距离:黄色方块移动距离 * 大图片最大移动距离 / 黄色方块最大移动距离
  let bigImg = document.querySelector('.big-img');
  // 获取大图最大移动距离
  let bigMax = bigImg.offsetWidth - big.offsetWidth;
  let bigX = maskX * bigMax / maskXMax;
  let bigY = maskY * bigMax / maskYMax;
  console.log(bigX, bigY);
  // 注意要反方向移动
  bigImg.style.left = -bigX + 'px';
  bigImg.style.top = -bigY + 'px';
})

四、附:完整代码

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <style>
      /*预览区域,相对定位,方便大图片盒子去绝对定位*/
      .preview_img {
        position: relative;
        width: 398px;
        height: 398px;
      }
      /*大图片盒子,起初隐藏,采用绝对定位固定到合适位置*/
      .big {
        display: none;
        position: absolute;
        left: 410px;
        top: 0;
        width: 500px;
        height: 500px;
        z-index: 999;
        border: 1px solid #ccc;
        overflow: hidden;/*图片溢出隐藏*/
      }
      /*大图片*/
      .big-img {
        position: absolute;
        top: 0;
        left: 0;
      }
      /*黄色方块放大镜*/
      .mask {
        display: none;
        position: absolute;
        top: 0;
        left: 0;
        width: 300px;
        height: 300px;
        background: #FEDE4F;
        opacity: .5;
        border: 1px solid #ccc;
        cursor: move;
      }

    </style>
  </head>

  <body>
    <!-- 预览区域 -->
    <div class="preview_img">
      <!--小图片-->
      <img src="img/123.jpg" width="398" height="398" alt="">
      <!--黄色方块:放大镜-->
      <div class="mask"></div>
      <!--大盒子与大图片-->
      <div class="big">
        <!--正常场景下此处放分辨率高的大图,这里模拟大图,改变了宽高-->
        <img src="img/123.jpg" width="800" height="800" alt="" class="big-img">
      </div>
    </div>
  </body>
  <script>
    // 获取元素
    const previewImg = document.querySelector('.preview_img');
    const mask = document.querySelector('.mask');
    const big = document.querySelector('.big');
    // 预览区域添加鼠标移入移出事件

    // 鼠标移入,显示大图片盒子与黄色方块
    previewImg.addEventListener('mouseover', function() {
      mask.style.display = 'block';
      big.style.display = 'block';
    })

    // 鼠标移出,隐藏大图片盒子与黄色方块
    previewImg.addEventListener('mouseout', function() {
      mask.style.display = 'none';
      big.style.display = 'none';
    })

    // 放大镜跟随鼠标移动,且不能小于0,不能大于最大移动距离
    previewImg.addEventListener('mousemove', function(e) {
      // 获取鼠标在盒子内的坐标
      let mouseX = e.pageX - this.offsetLeft;
      let mouseY = e.pageY - this.offsetTop;

      // 计算放大镜的top 与left,使得鼠标在放大镜中央
      let maskX = mouseX - mask.offsetWidth / 2;
      let maskY = mouseY - mask.offsetHeight / 2;

      // 计算放大镜最大的移动距离
      let maskXMax = this.offsetWidth - mask.offsetWidth;
      let maskYMax = this.offsetHeight - mask.offsetHeight;

      // 最小移动距离不得小于0,最大移动距离不得超过所计算的最大移动距离
      if (maskX <= 0) {
        maskX = 0;
      } else if (maskX >= maskXMax) {
        maskX = maskXMax;
      }
      if (maskY <= 0) {
        maskY = 0;
      } else if (maskY >= maskYMax) {
        maskY = maskYMax;
      }

      // 为放大镜的left top赋值,实现移动
      mask.style.left = maskX + 'px';
      mask.style.top = maskY + 'px';

      // 大图移动距离:黄色方块移动距离 * 大图片最大移动距离 / 黄色方块最大移动距离
      let bigImg = document.querySelector('.big-img');
      // 获取大图最大移动距离
      let bigMax = bigImg.offsetWidth - big.offsetWidth;
      let bigX = maskX * bigMax / maskXMax;
      let bigY = maskY * bigMax / maskYMax;
      console.log(bigX, bigY);
      // 注意要反方向移动
      bigImg.style.left = -bigX + 'px';
      bigImg.style.top = -bigY + 'px';
    })

  </script>

</html>