Component infrastructure

The end of the complete code can be directly copied to use

  • Objective: To encapsulate picture preview component and realize mouse hover switching effect

  • Landing Code:

    <template>
      <div class="goods-image">
        <div class="middle">
          <img :src="images[currIndex]" alt="">
        </div>
        <ul class="small">
          <li v-for="(img,i) in images" :key="img" :class="{active:i===currIndex}">
            <img @mouseenter="currIndex=i" :src="img" alt="">
          </li>
        </ul>
      </div>
    </template>
    <script>
    import { ref } from 'vue'
    export default {
      name: 'GoodsImage'.props: {
        images: {
          type: Array.default: () = > []
        }
      },
      setup (props) {
        const currIndex = ref(0)
        return { currIndex }
      }
    }
    </script>
    <style scoped lang="less">
    .goods-image {
      width: 480px;
      height: 400px;
      position: relative;
      display: flex;
      .middle {
        width: 400px;
        height: 400px;
        background: #f5f5f5;
      }
      .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

Picture magnifier

  • Objective: To realize the function of picture magnifier

  • Steps:

    • First prepare the big picture container and mask container
    • Then use the@vueuse/coretheuseMouseInElementMethod to get an offset based on the element
    • Calculate the mask container location and large container background location exposed data for template use
  • Landing Code:

    <template>
      <div class="goods-image">
    + // Achieve a large layout effect on the right (enlarge the background image by 4 times)
    + 
            
    <div class="middle"> <img :src="images[currIndex]" alt=""> + // Prepare the mask container to be moved +
    </div> <ul class="small"> <li v-for="(img,i) in images" :key="img" :class="{active:i===currIndex}"><img @mouseenter="currIndex=i" :src="img" alt=""> </li> </ul> </div> </template> <script> import { ref } from 'vue' export default { name: 'GoodsImage', props: { images: { type: Array, default: () => []}}, setup (props) { const currIndex = ref(0) return { currIndex } } } </script> <style scoped lang="less"> .goods-image { width: 480px; height: 400px; position: relative; display: flex;+ z-index: 500; + // Large image style on the right + .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; background: #f5f5f5; + position: relative; + cursor: move; + // Mask style + .layer { + width: 200px; + height: 200px; + background: rgba (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: 2px solid @xtxColor; } } } } </style> Copy the code

Install vueuse

  • NPM I @ vueuse/[email protected]

    The current 5.3.0 version is relatively stable

  • Vueuse provides the basic use of listening into a specified scope method

    import { useMouseInElement } from '@vueuse/core'
    const { elementX, elementY, isOutside } = useMouseInElement(target)
    Copy the code

    The target argument to the method represents the DOM object being listened on; Return the value elementX, elementY specifies the position information left and top in the upper left corner of the DOM. IsOutside indicates whether it is in the DOM scope, and true indicates that it isOutside the scope. False indicates the range.

Function implementation

<div v-if="isShow" class="large" :style="[{ backgroundImage: `url(${images[currIndex]})` }, bgPosition]"></div>
<div class="middle" ref="target">
   <img :src="images[currIndex]" alt="" />
   <div class="layer" v-if="isShow" :style="[position]"></div>
</div>

setup () {
// The monitored area
const target = ref(null)
// Controls the display and hiding of mask layers and preview images
const isShow = ref(false)
// Define the coordinates of the mask
const position = reactive({
      left: 0.top: 0
})
// Preview the coordinates of the large image on the right
const bgPosition = reactive({
      backgroundPositionX: 0.backgroundPositionY: 0
})

return { position, bgPosition, target, isShow }
}
Copy the code
const { elementX, elementY, isOutside } = useMouseInElement(target)
  // Listen for value changes based on the listener
  watch([elementX, elementY, isOutside], () = > {
    // Display and hide by flag bitisShow.value = ! isOutside.valueif (isOutside.value) return
    // X coordinate range control
    if (elementX.value < 100) {
      / / on the left side of the
      position.left = 0
    } else if (elementX.value > 300) {
      / / on the right side
      position.left = 200
    } else {
      / / in the middle
      position.left = elementX.value - 100
    }
    // control the range of Y coordinates
    if (elementY.value < 100) {
      position.top = 0
    } else if (elementY.value > 300) {
      position.top = 200
    } else {
      position.top = elementY.value - 100
    }
    // Calculate how far the preview moves
    bgPosition.backgroundPositionX = -position.left * 2 + 'px'
    bgPosition.backgroundPositionY = -position.top * 2 + 'px'
    // Calculate the location of the mask layer
    position.left = position.left + 'px'
    position.top = position.top + 'px'
  })
Copy the code

The complete code

<template>
  <div class="goods-image">
    <div v-if="isShow" class="large" :style="[{ backgroundImage: `url(${images[currIndex]})` }, bgPosition]"></div>
    <div class="middle" ref="target">
      <img :src="images[currIndex]" alt="" />
      <div class="layer" v-if="isShow" :style="[position]"></div>
    </div>
    <ul class="small">
      <li v-for="(img, i) in images" :key="img" :class="{ active: i === currIndex }">
        <img @mouseenter="currIndex = i" :src="img" alt="" />
      </li>
    </ul>
  </div>
</template>
<script>
import { ref, watch, reactive } from 'vue'
import { useMouseInElement } from '@vueuse/core'
export default {
  name: 'GoodsImage'.props: {
    images: {
      type: Array.default: () = > []
    }
  },
  setup (props) {
    const currIndex = ref(0)
    const target = ref(null)
    const isShow = ref(false)
    const position = reactive({
      left: 0.top: 0
    })
    const bgPosition = reactive({
      backgroundPositionX: 0.backgroundPositionY: 0
    })
    const { elementX, elementY, isOutside } = useMouseInElement(target)
    watch([elementX, elementY, isOutside], () = >{ isShow.value = ! isOutside.valueif (isOutside.value) return
      if (elementX.value <= 100) {
        position.left = 0
      } else if (elementX.value >= 300) {
        position.left = 200
      } else {
        position.left = elementX.value - 100
      }
      if (elementY.value <= 100) {
        position.top = 0
      } else if (elementY.value >= 300) {
        position.top = 200
      } else {
        position.top = elementY.value - 100
      }
      bgPosition.backgroundPositionX = -position.left * 2 + 'px'
      bgPosition.backgroundPositionY = -position.top * 2 + 'px'
      position.left += 'px'
      position.top += 'px'
    })
    return { currIndex, target, isShow, 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;
    background: #f5f5f5;
     position: relative;
    cursor: move;
    .layer {
      width: 200px;
      height: 200px;
      background: rgba(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