分享一个 Vue3 写的放大镜组件

使用方法:

<script  lang="ts" setup>
import ZoomVue from '@/components/Zoom.vue';

</script>

<template>
  <div class="box">
    <ZoomVue
      smallImg="//img13.360buyimg.com/n1/s350x467_jfs/t1/218810/22/23762/218396/637f20d4Eb088c1e6/c45ffbf83bdb9059.jpg!cc_350x467.avif"
      bigImg="//img13.360buyimg.com/n1/s750x1000_jfs/t1/218810/22/23762/218396/637f20d4Eb088c1e6/c45ffbf83bdb9059.jpg!cc_750x1000.avif">
    </ZoomVue>
  </div>
</template>

<style lang="scss" scoped>
.box {
  margin-top: 100px;
  margin-left: 30px;
}
</style>

具体实现:

<script  lang="ts" setup>
import { computed } from '@vue/reactivity';
import { onMounted, ref } from 'vue';

// types
export interface Props {
  smallImg: string,
  bigImg: string,
}

//vars
const props = defineProps<Props>();

//states
const zoomBox = ref<HTMLElement>();
const smallBox = ref<HTMLElement>();
const maskBox = ref<HTMLElement>();
const bigBox = ref<HTMLElement>();


// methods
function handleMoveOnSmall(e: MouseEvent) {
  const width = maskBox.value!.offsetWidth / 2;
  const height = maskBox.value!.offsetHeight / 2;

  const deltaX = Math.min(Math.max(0, e.pageX - zoomBox.value!.offsetLeft - width), smallBox.value!.offsetWidth - maskBox.value!.offsetWidth);
  const deltaY = Math.min(Math.max(0, e.pageY - zoomBox.value!.offsetTop - height), smallBox.value!.offsetHeight - maskBox.value!.offsetHeight)

  maskBox.value!.style.left = deltaX + "px";
  maskBox.value!.style.top = deltaY + "px";

  const rate = bigBox.value!.offsetWidth / maskBox.value!.offsetWidth;

  bigBox.value!.style.backgroundPositionX = -deltaX * rate + "px";
  bigBox.value!.style.backgroundPositionY = -deltaY * rate + "px";
}

function handleMouseEnter() {
  maskBox.value!.style.display = "block";
  bigBox.value!.style.display = "block";

  const rate = bigBox.value!.offsetWidth / maskBox.value!.offsetWidth;
  bigBox.value!.style.backgroundSize = smallBox.value!.offsetWidth * rate + "px";
}

function handleMouseLeave() {
  maskBox.value!.style.display = "none";
  bigBox.value!.style.display = "none";
}

function loadImage() {
  bigBox.value!.style.backgroundImage = `url("${bigBox.value!.dataset.img}")`;
}

onMounted(async () => {
  loadImage();
})
</script>

<template>
  <div class="zoom" ref="zoomBox">
    <div class="small" @mousemove="handleMoveOnSmall" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave"
      ref="smallBox">
      <img :src="smallImg" alt="商品图片">
      <div class="mask" ref="maskBox"></div>
    </div>
    <div class="big" ref="bigBox" :data-img="bigImg">
    </div>
  </div>
</template>

<style lang="scss" scoped>
.zoom {
  position: relative;

  .small {
    position: relative;
    width: 300px;
    height: 400px;

    img {
      width: 100%;
    }

    .mask {
      position: absolute;
      top: 0;
      left: 0;
      width: 160px;
      height: 160px;
      background-color: rgb(255, 255, 0, 0.3);
      cursor: move;
      display: none;
    }
  }

  .big {
    position: absolute;
    top: 0;
    left: 301px;
    width: 400px;
    height: 400px;
    overflow: hidden;
    display: none;
    background-repeat: no-repeat;
    // background-size: 750px;
    // background-image: url("//img13.360buyimg.com/n1/s350x467_jfs/t1/218810/22/23762/218396/637f20d4Eb088c1e6/c45ffbf83bdb9059.jpg");
    background-position: 0px 0px;
  }
}
</style>
vuejs·javascript
204 views
Comments
登录后评论
Sign In
·

帖子不能修改的吗 fearful

·

手动赞

·

grin 一个建议,少用感叹号! 用 ?? 做空检查,可以避免一些奇奇怪怪的 bug