Vue3 — Own encapsulation similar to the magnifying glass effect components of JINGdong product details page

Finish the basic layout first

To complete the image switching effect, passmouseenterEvent switch image

Be born code

<template>
  <div class="goods-image">
    <! -- Preview large image -->
    <div class="large" v-show="show" :style="[{ backgroundImage: `url(${images[currIndex]})` }, bgPosition]"></div>
    <! -- Commodity picture -->
    <div class="middle">
      <! -- Commodity picture -->
      <img ref="target" :src="images[currIndex]" alt="" />
      <! Mouse over the image mask -->
      <div class="layer" v-show="show" :style="[position]"></div>
    </div>
    <! -- Thumbnail image -->
    <ul class="small">
      <li v-for="(img, i) in images" :key="img" :class="{ active: i === currIndex }">
        <! -- Move the mouse over the small picture next to the large picture of the commodity and the position of the large picture of the commodity will be displayed -->
        <img @mouseenter="currIndex = i" :src="img" alt="" />
      </li>
    </ul>
  </div>
</template>
<script>
import { reactive, ref, watch } from 'vue'
import { useMouseInElement } from '@vueuse/core'
export default {
  name: 'GoodsImage'.props: {
    images: {
      type: Array.default: () = >[]}},setup(props) {
    // Control the display and hiding of the preview large image and mask layer
    const show = ref(false)
    // Control the large picture of the commodity to display that picture
    const currIndex = ref(0)
    // ref gets the DOM element
    const target = ref(null)
    // Record the coordinates of the mask translucency map in the commodity picture
    const position = reactive({
      top: 0.left: 0
    })
    // Record the coordinates of the area covered by the mask layer in the preview
    const bgPosition = reactive({
      backgroundPositionX: 0.backgroundPositionY: 0
    })
    // The method useMouseInElement provided by third-party Vueuse gets the coordinates of the mouse in a certain area
    const { elementX, elementY, isOutside } = useMouseInElement(target)
    // The listener monitors the coordinates when the mouse enters the large image of the commodity to manipulate the mask layer and preview the effect of the large image
    watch([elementX, elementY, isOutside], () = > {
      Isisoutside. value: true indicates that the mouse is not in the target element; false indicates that the mouse is in the target element
      // True does not record coordinates to avoid performance loss
      if (isOutside.value) {
        // Do not display mask layer and preview large image without mouse over target element
        show.value = false
        return
      }
      // Mouse over the target element to display the mask layer and preview the large image
      show.value = true
      // Determine the boundary value according to the size of the mask layer and the size of the commodity image
      // left boundary values (left and right)
      if (elementX.value < 100) {
        position.left = 0
      } else if (elementX.value > 300) {
        position.left = 200
      } else {
        position.left = elementX.value - 100
      }
      // Top boundary values (top, bottom)
      if (elementY.value < 100) {
        position.top = 0
      } else if (elementY.value > 300) {
        position.top = 200
      } else {
        position.top = elementY.value - 100
      }
      // The coordinates of the commodity image covered by the mask layer in the preview big picture, plus units
      bgPosition.backgroundPositionY = -position.top * 2 + 'px'
      bgPosition.backgroundPositionX = -position.left * 2 + 'px'
      // Mask layer relative to the upper left corner of the commodity picture, plus units
      position.top += 'px'
      position.left += 'px'
    })
    // return it to the template
    return { currIndex, show, target, position, bgPosition }
  }
}
</script>
<style scoped lang="less">
.goods-image {
  width: 480px;
  height: 400px;
  position: relative;
  display: flex;
  z-index: 500;
  .large {
    position: absolute;
    top: 0;
    left: 412px;
    width: 400px;
    height: 400px;
    box-shadow: 0 0 10px rgba(0.0.0.0.1);
    background-repeat: no-repeat;
    background-size: 800px 800px;
    background-color: #f8f8f8;
  }
  .middle {
    width: 400px;
    height: 400px;
    position: relative;
    cursor: move;
    .layer {
      width: 200px;
      height: 200px;
      background: rgba(0.0.0.0.2);
      left: 0;
      top: 0;
      position: absolute; }}.small {
    width: 80px;
    li {
      width: 68px;
      height: 68px;
      margin-left: 12px;
      margin-bottom: 15px;
      cursor: pointer;
      &:hover,
      &.active {
        border: 2pxsolid @xtxColor; }}}}</style>
Copy the code

The final result