The principle and specific implementation of the JavaScript image magnifying glass, using Vue to demonstrate the code, other frameworks are similar

1. Analysis principle        

        The product details page of an online shopping mall often uses the design of a picture magnifying glass. Taking JD.com as an example, the yellow layer part is the area that needs to be enlarged and displayed in the large frame on the right:

Analyze the above picture:

  • There are four areas : image area (width and height are recorded as imgX, imgY), a mask (yellow layer part) (width and height are recorded as maskX, maskY), an enlarged image area (width and height are recorded as bigImgX, bigImgY) , large image (width and height are recorded as bigX, bigY).
  • First determine the movement of the mask layer : theoretically, the mouse should be located at the center of the mask. But when the upper left corner of the mask has already coincided with the upper left corner of the picture, move the mouse and keep the position of the mask layer fixed. In other words, it has moved to the boundary and cannot go further. Similarly, the lower right corner, upper right corner, and lower left corner also keep the position of the mask layer fixed.
  1. The left distance of the mask layer should be the left distance of the mouse minus half of the mask width: event.offsetX - maskX / 2.
  2. The distance from the head of the mask layer to top should be the distance from the top of the mouse minus half of the mask height: event.offsetY - maskY / 2.
  3. When left < 0, left is fixed at 0; when left > imgX - maskX, left is fixed at imgX - maskX.
  4. When top < 0, top is fixed at 0; when top > imgY - maskY, top is fixed at imgY - maskY.

  • Since the enlarged image area is actually an enlargement of the mask area, and in order to ensure that the image is not stretched, the enlarged image area is actually an enlargement of the mask layer, then maskX / bigImgX = maskY / bigImgY. Of course, the big picture (bigX, bigY) is an enlargement of the small picture. Then imgX/bigX = imgY/bigY. To ensure that the details of the display area are just completed during the process of moving the mask, maskX / bigImgX = maskY / bigImgY = imgX / bigX = imgY / bigY. In short, the ratio of the mask layer to the enlarged image area should be consistent with the enlarged image size.
  • Assuming that the magnification ratio is 5 times and the mask layer is 30*40, the enlarged image area should be 150*200. If the width and height of the small image are 50*50, the width and height of the large image should be 250*250. The offset of the large image in the enlarged image area should be a multiple times the offset of the mask:
  1. When left < 0, left is fixed at 0; when left > imgX - maskX, left is fixed at imgX - maskX, and the left side of the large image is offset by -5 * left.
  2. When top < 0, top is fixed at 0; when top > imgY - maskY, top is fixed at imgY - maskY, and the top of the large image is offset by -5 * top.

In the above analysis process, we can see that there are many offset calculations, and it is determined that relative positioning and absolute positioning should be used.

2. Realization

        For convenience, the author uses vue to demonstrate here, and the same principle applies to other frameworks.

Four areas:

        <div class="preview">
          <img :src="imgUrl" v-if="imgUrl" class="img" @mousemove="(e) => handlerMouseMove(e)">
          <el-image :src="defaultImg" alt="" class="img" v-else />

          <!-- 遮罩 -->
          <div class="mask" ref="mask"></div>

          <!-- 放大的图片显示区域 -->
          <div class="big">
            <img :src="bigImgUrl" ref="bigImg" />
          </div>
        </div>

Set the style: 

  • Set the width and height of the image display area to 50*50.
  • The mask and large image display area are not displayed by default, and they are displayed only when the mouse is moved over the image.
  • The mask layer is set to 25*20, absolutely positioned, and initialized to the upper left corner.
  • Set the display area of ​​the large image, and set it to 125*100 according to the 5 times ratio.
  • The big picture is positioned relative to the big picture display area, initially at the upper left corner.
.preview {
  width: 50px;
  height: 50px;
  margin: 0 auto;
  position: relative;

  .img {
    width: 50px;
    height: 50px;
    position: relative;
    top: 0;
    left: 0;

    &:hover {
      cursor: crosshair;
    }
  }

  .img:hover~.mask,
  .img:hover~.big {
    display: block;
  }

  .mask {
    width: 25px;
    height: 20px;
    background: rgb(109, 109, 109);
    position: absolute;
    left: 0;
    top: 0;
    display: none;
    transform: translate3d(0px, 0px, 0px);
    pointer-events: none;
  }

  .big {
    width: 125px;
    height: 100px;
    position: absolute;
    top: 0;
    left: 110%;
    overflow: hidden;
    z-index: 998;
    display: none;
    background: white;
    border-radius: 2px;

    img {
      width: 250px;
      height: 250px;
      position: absolute;
      left: 0;
      top: 0;
    }
  }
}

Mouse position: event.offsetX, event.offsetY, calculate the left and top according to the above, and position the mask mask and the big image display area respectively:

    handlerMouseMove(event) {
      let mask = this.$refs.mask;
      let big = this.$refs.big;

      let left = event.offsetX - mask.offsetWidth / 2
      let top = event.offsetY - mask.offsetHeight / 2
      //当left < 0,left固定为0;当left > imgX - maskX,left固定为imgX - maskX,50-25=25
      if (left < 0) {
        left = 0
      } else if (left > 25) {
        left = 25
      }
      //当top < 0,top固定为0;当top > imgY - maskY,top固定为imgY - maskY,50-20=30
      if (top < 0) {
        top = 0
      } else if (top > 30) {
        top = 30
      }
      mask.style.left = left + 'px'
      mask.style.top = top + 'px'
      //大图左侧偏移 -5 * left,125/25 === 100/20 === 250/50 === 250/50 === 5
      big.style.left = -5 * left + 'px'
      //大图顶部偏移 -5 * top
      big.style.top = -5 * top + 'px'
    },

Guess you like

Origin blog.csdn.net/sxww_zyt/article/details/130841275
Recommended