前端實現商品放大鏡效果(Vue3完整實現)
前言
在電商類項目中,商品圖片的細節展示至關重要。放大鏡效果能顯著提升用戶體驗,允許用戶在不跳轉頁面的情況下查看高清細節。本文將基于Vue3實現一個高性能的放大鏡組件,完整解析實現原理,并提供可直接復用的代碼。
一、實現原理與關鍵技術
1. 核心交互邏輯
- 三區域聯動:縮略圖區域 ? 遮罩層 ? 放大區域
- 坐標映射:通過鼠標位置計算放大比例
- 反向運動:放大圖移動方向與遮罩層相反
2. 關鍵技術點
技術點 | 作用說明 |
---|---|
事件監聽 | 實時獲取鼠標位置 |
CSS transform | 實現平滑位移效果 |
邊界檢測 | 防止遮罩層溢出 |
節流函數 | 優化頻繁觸發事件性能 |
二、Vue3完整實現代碼
1. 組件模板 (Magnifier.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. 邏輯實現
<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.offsetWidthconst imgHeight = thumbImg.value.offsetHeightconst offsetX = (mouseX.value / imgWidth) * 100const offsetY = (mouseY.value / imgHeight) * 100return {backgroundImage: `url(${props.zoomSrc})`,backgroundPosition: `${offsetX}% ${offsetY}%`,backgroundSize: `${imgWidth * props.scale}px ${imgHeight * props.scale}px`}
})// 鼠標移動處理(帶邊界檢測)
const handleMouseMove = (e) => {if (!thumbImg.value) returnconst rect = thumbImg.value.getBoundingClientRect()let x = e.clientX - rect.leftlet y = e.clientY - rect.top// 邊界約束const maxX = rect.width - props.maskSize.w/2const minX = props.maskSize.w/2const maxY = rect.height - props.maskSize.h/2const minY = props.maskSize.h/2mouseX.value = Math.max(minX, Math.min(x, maxX))mouseY.value = Math.max(minY, Math.min(y, maxY))
}
</script>
3. 樣式設計
<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>
三、使用示例
<template><Magnifierthumb-src="/product-thumb.jpg"zoom-src="/product-zoom.jpg":scale="3":mask-size="{ w: 150, h: 150 }"/>
</template>
四、實現效果優化建議
-
圖片預加載:
// 在組件掛載時預加載大圖 onMounted(() => {new Image().src = props.zoomSrc })
-
節流處理:
使用lodash.throttle
優化頻繁觸發的mousemove事件 -
移動端適配:
添加touch事件支持:@touchmove="handleTouchMove"const handleTouchMove = (e) => {handleMouseMove(e.touches[0]) }
五、總結
關鍵知識點回顧
要點 | 實現方案 |
---|---|
坐標映射 | 通過百分比計算背景圖位移 |
性能優化 | 節流函數 + 預加載 |
邊界控制 | 動態約束鼠標坐標范圍 |
響應式設計 | 通過props參數靈活配置 |