前端实现商品放大镜效果(Vue3完整实现)

前言
在电商类项目中,商品图片的细节展示至关重要。放大镜效果能显著提升用户体验,允许用户在不跳转页面的情况下查看高清细节。本文将基于Vue3实现一个高性能的放大镜组件,完整解析实现原理,并提供可直接复用的代码。
一、实现原理与关键技术
1. 核心交互逻辑
- 三区域联动:缩略图区域 ➜ 遮罩层 ➜ 放大区域
- 坐标映射:通过鼠标位置计算放大比例
- 反向运动:放大图移动方向与遮罩层相反
2. 关键技术点
技术点 | 作用说明 |
---|---|
事件监听 | 实时获取鼠标位置 |
CSS transform |
实现平滑位移效果 |
边界检测 | 防止遮罩层溢出 |
节流函数 | 优化频繁触发事件性能 |
二、Vue3完整实现代码
1. 组件模板 (Magnifier.vue
)
vue
<template>
<div class="magnifier-container">
<!-- 缩略图区域 -->
<div
class="thumbnail-box"
@mousemove="handleMouseMove"
@mouseenter="showOverlay = true"
@mouseleave="showOverlay = false"
>
<img
ref="thumbImg"
:src="thumbSrc"
alt="商品图"
class="thumbnail"
>
<!-- 遮罩层 -->
<div
v-show="showOverlay"
class="mask"
:style="maskStyle"
></div>
</div>
<!-- 放大区域 -->
<div
v-show="showOverlay"
class="zoom-box"
:style="zoomBoxStyle"
>
<div
class="zoom-image"
:style="zoomImageStyle"
></div>
</div>
</div>
</template>
2. 逻辑实现
vue
<script setup>
import { ref, computed } from 'vue'
const props = defineProps({
thumbSrc: String, // 缩略图地址
zoomSrc: String, // 高清图地址
scale: { // 放大倍数
type: Number,
default: 2
},
maskSize: { // 遮罩层尺寸
type: Object,
default: () => ({ w: 200, h: 200 })
}
})
const showOverlay = ref(false)
const thumbImg = ref(null)
// 鼠标位置状态
const mouseX = ref(0)
const mouseY = ref(0)
// 遮罩层样式
const maskStyle = computed(() => ({
width: `${props.maskSize.w}px`,
height: `${props.maskSize.h}px`,
left: `${mouseX.value - props.maskSize.w/2}px`,
top: `${mouseY.value - props.maskSize.h/2}px`
}))
// 放大区域样式
const zoomBoxStyle = computed(() => ({
width: `${props.maskSize.w * props.scale}px`,
height: `${props.maskSize.h * props.scale}px`
}))
// 放大图位移计算
const zoomImageStyle = computed(() => {
if (!thumbImg.value) return {}
const imgWidth = thumbImg.value.offsetWidth
const imgHeight = thumbImg.value.offsetHeight
const offsetX = (mouseX.value / imgWidth) * 100
const offsetY = (mouseY.value / imgHeight) * 100
return {
backgroundImage: `url(${props.zoomSrc})`,
backgroundPosition: `${offsetX}% ${offsetY}%`,
backgroundSize: `${imgWidth * props.scale}px ${imgHeight * props.scale}px`
}
})
// 鼠标移动处理(带边界检测)
const handleMouseMove = (e) => {
if (!thumbImg.value) return
const rect = thumbImg.value.getBoundingClientRect()
let x = e.clientX - rect.left
let y = e.clientY - rect.top
// 边界约束
const maxX = rect.width - props.maskSize.w/2
const minX = props.maskSize.w/2
const maxY = rect.height - props.maskSize.h/2
const minY = props.maskSize.h/2
mouseX.value = Math.max(minX, Math.min(x, maxX))
mouseY.value = Math.max(minY, Math.min(y, maxY))
}
</script>
3. 样式设计
vue
<style scoped>
.magnifier-container {
display: flex;
gap: 20px;
}
.thumbnail-box {
position: relative;
cursor: crosshair;
overflow: hidden;
}
.thumbnail {
display: block;
max-width: 600px;
height: auto;
}
.mask {
position: absolute;
background: rgba(255, 255, 255, 0.3);
border: 1px solid #ccc;
pointer-events: none;
}
.zoom-box {
border: 1px solid #ddd;
overflow: hidden;
}
.zoom-image {
width: 100%;
height: 100%;
background-repeat: no-repeat;
}
</style>
三、使用示例
vue
<template>
<Magnifier
thumb-src="/product-thumb.jpg"
zoom-src="/product-zoom.jpg"
:scale="3"
:mask-size="{ w: 150, h: 150 }"
/>
</template>
四、实现效果优化建议
-
图片预加载:
javascript// 在组件挂载时预加载大图 onMounted(() => { new Image().src = props.zoomSrc })
-
节流处理 :
使用
lodash.throttle
优化频繁触发的mousemove事件 -
移动端适配 :
添加touch事件支持:
vue@touchmove="handleTouchMove" const handleTouchMove = (e) => { handleMouseMove(e.touches[0]) }
五、总结
关键知识点回顾
要点 | 实现方案 |
---|---|
坐标映射 | 通过百分比计算背景图位移 |
性能优化 | 节流函数 + 预加载 |
边界控制 | 动态约束鼠标坐标范围 |
响应式设计 | 通过props参数灵活配置 |