一、放大镜

1. 需求

需求:实现一个电商放大镜的效果(放大3倍);

  1. 默认展示原图

  2. 当鼠标移入原图盒子时,原图盒子中的遮罩层以及装大图的盒子都要出现;

  3. 当鼠标在原图盒子中移动时,遮罩层要跟随鼠标一起移动,但是盒子不能超出原图的盒子边界(带边界限制的鼠标跟随);

  4. 大图展示的部分正好是盖住的原图部分;

  5. 遮罩层和大图运动方向相反,遮罩层在原图盒子中移动距离x,大图需要移动-3x的距离;

  6. 当鼠标移出原图时,遮罩层和大图都要消失;

2. 思路

思路:放大镜放大3倍

  1. 有两个大盒子,一个用来装原图的 box1,另一个是用来装大图的 box2;box1 和 box2 是宽高是相等的;

  2. box1下面有一个遮罩层 mask,这个遮罩层盖住 box1 部分和 box2 露出的大图的部分是相同的,所以有一个比例关系:mask 的宽高 / box1 的宽高 = box2 / 大图片的尺寸;

  3. mask 要相对于 box1 绝对定位,大图片相对于 box2 绝对定位;

  4. 监听 box1 的 onmouseenter 事件,当事件触发时,设置 mask 和 box2 的 display: block;

  5. 鼠标移动时 mask 要跟随鼠标,需要监听 box1 的 onmousemove 事件,在事件函数中实现鼠标带边界的中心跟随;

  6. 在 mask 在 box1 中移动的时候,大图片 bigImg 要向相反的方向移动;如果 mask 移动 x,那么 bigImg 需要移动 -3x 的距离;

  7. 当鼠标移出 box1 的时候,mask 和 box2 消失,所以需要监听 box1 的 leave 事件,在事件函数中把 mask 和 box2 的 display 设置为 none

3. 鼠标跟随

  1. // 实现一个鼠标跟随效果:
  2. // 页面中有一个盒子 BOX,当鼠标移动的时候,要让盒子 box 跟随鼠标,保持鼠标处于盒子的中心位置;
  3. // ?? 怎么实现??
  4. // 1. 监听 document 的 onmousemove 事件
  5. // 2. 实时获取鼠标的位置,把鼠标的位置坐标设置成元素的 left 和 top
  6. let $ = selector => document.querySelector(selector);
  7. let box = $('.box');
  8. document.onmousemove = function (e) {
  9. // console.log(e.clientX, e.clientY);
  10. // 元素的 left 值和 top 值设置的是元素的左上角点距离 body 的左边框和上边框的距离;直接设置会导致鼠标一直处于元素的左上角
  11. // box.style.left = e.clientX + 'px';
  12. // box.style.top = e.clientY + 'px';
  13. // 为了让鼠标处于盒子的中心位置,因为元素在跟着鼠标动,鼠标的位置是不能改的,为了让鼠标在盒子中心位置,所以需要让 clientX 减去 半个盒子的宽,clientY - 半个盒子的高。
  14. let left = e.clientX - box.offsetWidth / 2;
  15. let top = e.clientY - box.offsetHeight / 2;
  16. // 把 left 和 top 设置给元素
  17. box.style.left = left + 'px';
  18. box.style.top = top + 'px';
  19. };

4. 设置边界

  1. // 鼠标跟随,盒子不能超出浏览器的可视窗口
  2. // 边界限制的原理:用户看到的是盒子不能超过浏览器窗口;事实上是 left 和 top 不能超过某个值;
  3. // let 和 top 的最小值0;
  4. // 如何求 left 和 top 的最大值?
  5. // left 的最大值 = 浏览器可视窗口的宽 - 盒子宽
  6. // top 的最大值 = 浏览器可视窗口的高 - 盒子高
  7. function win(attr) {
  8. return document.documentElement[attr] || document.body[attr];
  9. }
  10. let $ = selector => document.querySelector(selector);
  11. let box = $('#box');
  12. // 求left和top的最大值
  13. let maxL = win('clientWidth') - box.offsetWidth;
  14. let maxT = win('clientHeight') - box.offsetHeight;
  15. // left和top的最小值
  16. let minL = 0;
  17. let minT = 0;
  18. // 监听 document 的 onmousemove 事件,在事件中实时计算盒子的 left 和 top;
  19. document.onmousemove = function (e) {
  20. // 1. 根据鼠标的位置计算盒子的 left 和 top
  21. let left = e.clientX - box.offsetWidth / 2;
  22. let top = e.clientY - box.offsetHeight / 2;
  23. // 2. 判断是否越界,如果越界就需要修正(比最小值还小,就等于最小值;比最大值还大,就等于最大值)
  24. if (left < minL) {
  25. left = minL;
  26. }
  27. if (left > maxL) {
  28. left = maxL;
  29. }
  30. if (top < minT) {
  31. top = minT;
  32. }
  33. if (top > maxT) {
  34. top = maxT;
  35. }
  36. // 3. 把 left 和 top 设置给元素
  37. box.style.left = left + 'px';
  38. box.style.top = top + 'px';
  39. };

二、具体实现

放大镜html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>放大镜</title>
  6. <style>
  7. * {
  8. margin: 0;
  9. padding: 0;
  10. }
  11. body {
  12. overflow: hidden;/*清浮动*/
  13. }
  14. .box1, .box2 {
  15. margin: 50px;
  16. position: relative;
  17. float: left;
  18. width: 300px;
  19. height: 300px;
  20. border: 1px solid red;
  21. overflow: hidden;
  22. }
  23. .box1 img {
  24. width: 100%;
  25. height: 100%;
  26. }
  27. .mask {
  28. display: none;
  29. position: absolute;
  30. top: 0;
  31. left: 0;
  32. width: 100px;
  33. height: 100px;
  34. background: rgba(0, 0, 0, .5);
  35. /*cursor: pointer; 小手*/
  36. /*cursor: not-allowed; 禁止*/
  37. cursor: move; /*十字 表示可以移动*/
  38. }
  39. .box2 {
  40. display: none;
  41. }
  42. .box2 img {
  43. position: absolute;
  44. width: 900px;
  45. height: 900px;
  46. }
  47. /*100 / 300 = 300 / 900*/
  48. </style>
  49. </head>
  50. <body>
  51. <div class="box1" id="box1">
  52. <img src="iphone.jpg" alt="">
  53. <div class="mask"
  54. id="mask"
  55. style="width: 100px; height: 100px;left: 0;top: 0;"></div>
  56. </div>
  57. <div class="box2" id="box2">
  58. <img src="iphone.jpg" class="bigImg" id="bigImg">
  59. </div>
  60. <script src="js/放大镜.js"></script>
  61. </body>
  62. </html>

放大镜js

  1. // 1. 获取元素
  2. let $ = selector => document.querySelector(selector);
  3. let box1 = $('.box1');
  4. let mask = $('.mask');
  5. let box2 = $('.box2');
  6. let bigImg = $('.bigImg');
  7. // 2. 监听 box1 的进入和移出,让 mask 和 box2 消失隐藏
  8. box1.onmouseenter = function () {
  9. mask.style.display = box2.style.display = 'block';
  10. };
  11. box1.onmouseleave = function () {
  12. mask.style.display = box2.style.display = 'none';
  13. };
  14. // 3. 实现在 box1 中移动鼠标 mask 中心有边界跟随,并且 bigImg 相应移动
  15. // 这些都是 mask 移动边界值(left、top 的最大值和最小值)
  16. let minL = 0;
  17. let minT = 0;
  18. let maxL = box1.clientWidth - parseFloat(mask.style.width);
  19. let maxT = box1.clientHeight - parseFloat(mask.style.height);
  20. box1.onmousemove = function (e) {
  21. // 3.1 获取鼠标的位置
  22. let left = e.clientX - box1.offsetLeft - parseFloat(mask.style.width) / 2;
  23. let top = e.clientY - box1.offsetTop - parseFloat(mask.style.height) / 2;
  24. // 3.2 对鼠标位置进行修正
  25. if (left < minL) {
  26. left = minL;
  27. }
  28. if (left > maxL) {
  29. left = maxL;
  30. }
  31. if (top < minT) {
  32. top = minT;
  33. }
  34. if (top > maxT) {
  35. top = maxT;
  36. }
  37. // 3.3 把修正后的值设置给 mask
  38. mask.style.left = left + 'px';
  39. mask.style.top = top + 'px';
  40. // 3.4 按照放大比例,设置 bigImg 的 left 和 top
  41. bigImg.style.left = -3 * left + 'px';
  42. bigImg.style.top = -3 * top + 'px';
  43. };

放大镜.png

1. 那么如果盒子不是设定好的呢?

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>放大镜</title>
  6. <!-- IMPORT CSS -->
  7. <link rel="stylesheet" href="css/reset.min.css">
  8. <style>
  9. .magnifier {
  10. box-sizing: border-box;
  11. margin: 20px auto;
  12. width: 550px;
  13. }
  14. .magnifier .abbre,
  15. .magnifier .origin {
  16. float: left;
  17. }
  18. .magnifier .abbre {
  19. position: relative;
  20. box-sizing: border-box;
  21. width: 200px;
  22. height: 150px;
  23. }
  24. .magnifier .abbre img {
  25. width: 100%;
  26. height: 100%;
  27. }
  28. .magnifier .abbre .mark {
  29. display: none;
  30. position: absolute;
  31. top: 0;
  32. left: 0;
  33. width: 80px;
  34. height: 60px;
  35. background: rgba(255, 0, 0, .3);
  36. cursor: move;
  37. }
  38. .magnifier .origin {
  39. display: none;
  40. position: relative;
  41. box-sizing: border-box;
  42. width: 250px;
  43. height: 250px;
  44. overflow: hidden;
  45. }
  46. .magnifier .origin img {
  47. position: absolute;
  48. top: 0;
  49. left: 0;
  50. }
  51. </style>
  52. </head>
  53. <body>
  54. <section class="magnifier clearfix">
  55. <!-- 左侧缩略图 -->
  56. <div class="abbre">
  57. <img src="images/1.jpg" alt="">
  58. <div class="mark"></div>
  59. </div>
  60. <!-- 右侧原图(大图) -->
  61. <div class="origin">
  62. <img src="images/2.jpg" alt="">
  63. </div>
  64. </section>
  65. <!--IMPORT JS-->
  66. <script src="js/jquery.min.js"></script>
  67. <script>
  68. let $abbre = $('.abbre'),
  69. $mark = $abbre.find('.mark'),
  70. $origin = $('.origin'),
  71. $originImg = $origin.find('img');
  72. //=>computedMark:计算MARK盒子的位置
  73. let abbreW = $abbre.outerWidth(),
  74. abbreH = $abbre.outerHeight(),
  75. abbreOffset = $abbre.offset(),
  76. markW = $mark.outerWidth(),
  77. markH = $mark.outerHeight(),
  78. originW = $origin.outerWidth(),
  79. originH = $origin.outerHeight(),
  80. originImgW = abbreW / markW * originW,
  81. originImgH = abbreH / markH * originH;
  82. //1.计算出大图的大小
  83. $originImg.css({
  84. width: originImgW,
  85. height: originImgH
  86. });
  87. function computedMark(ev) {
  88. //2.计算 MARK 的位置
  89. let markL = ev.pageX - abbreOffset.left - markW / 2,
  90. markT = ev.pageY - abbreOffset.top - markH / 2;
  91. let minL = 0,
  92. minT = 0,
  93. maxL = abbreW - markW,
  94. maxT = abbreH - markH;
  95. markL = markL < minL ? minL : (markL > maxL ? maxL : markL);
  96. markT = markT < minT ? minT : (markT > maxT ? maxT : markT);
  97. $mark.css({
  98. left: markL,
  99. top: markT
  100. });
  101. //3.控制大图移动移动的距离
  102. $originImg.css({
  103. left: -markL / abbreW * originImgW,
  104. top: -markT / abbreH * originImgH
  105. });
  106. }
  107. $abbre.mouseenter(function (ev) {
  108. $mark.css('display', 'block');
  109. $origin.css('display', 'block');
  110. computedMark(ev);
  111. }).mouseleave(function (ev) {
  112. $mark.css('display', 'none');
  113. $origin.css('display', 'none');
  114. }).mousemove(function (ev) {
  115. computedMark(ev);
  116. });
  117. </script>
  118. </body>
  119. </html>

2. 图片资源

1.jpg2.jpg