1. 效果图展示
2. 封装代码
<template>
<div class="goods-image">
<!-- 放大镜的位置 -->
<div
class="large"
:style="{ backgroundImage: `url(${images[currIndex]})`, ...largeStyle }"
v-show="!isOutside"
></div>
<!-- 左边的大图 -->
<div class="middle" ref="target">
<img :src="images[currIndex]" alt="" />
<!-- 遮罩层 -->
<div class="layer" v-show="!isOutside" :style="layerStyle"></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, reactive, watch } from 'vue'
import { useMouseInElement } from '@vueuse/core'
export default {
name: 'GoodsImage',
props: {
images: {
type: Array,
default: () => []
}
},
setup () {
const currIndex = ref(0)
const target = ref(null)
const { elementX, elementY, isOutside } = useMouseInElement(target)
const layerStyle = reactive({ top: '0px', left: '0px' })
const largeStyle = reactive({
'background-position-x': '0px',
'background-position-y': '0px'
})
watch([elementX, elementY, isOutside], () => {
// top, left 用来确定绝对定位下 遮罩元素 的位置
let top = elementY.value - 100
let left = elementX.value - 100
// 遮罩元素的位置不能移出 中图 所在范围
if (top > 200) top = 200
if (top < 0) top = 0
if (left > 200) left = 200
if (left < 0) left = 0
// 给遮罩元素赋值位置
layerStyle.top = top + 'px'
layerStyle.left = left + 'px'
// 给大图设置background-position的值,以移动位置的效果
largeStyle['background-position-x'] = -2 * left + 'px'
largeStyle['background-position-y'] = -2 * top + 'px'
})
return {
currIndex,
target,
elementX,
elementY,
isOutside,
layerStyle,
largeStyle
}
}
}
</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, 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>
3. 参数说明
return的参数
currIndex:图片的索引值
target:设置的目标元素
elementX:鼠标在目标元素中的X轴位置(参照为左上角)
elementY:鼠标在目标元素中的Y轴位置(参照为左上角)
isOutside:鼠标是否在目标元素中(值为Boolean)
layerStyle:是当前遮罩层的定位位置
largeStyle:是大图对应的定位位置
props参数
images:需要父组件传递图片信息进来,格式为Array
注意点:该组件的核心依旧使用了@vueuse/core
插件的useMouseInElement
方法,
elementX
,elementY
,isOutside
都是该方法的返回值