今天开发一个防某商城的商品图片放大镜,鼠标移动到图片位置时,右侧出现一个已放大的图片效果。
示例如下:
下图的图片的放大效果和小图的切换封装成了组件PicShow.vue
,可根据需求自行修改,如下:
第一步:组件代码使用
<template><div><!-- 大图、轮播图、放大镜 --><PicShow :images="imgList"/></div>
</template>
<script setup lang="ts">
const state = ref(['https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg','https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg','https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg','https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg'
])
</script >
第二步:PicShow.vue
组件代码,代码不多也比较简单,但写起来似乎并不太容易(感兴趣的朋友可以仔细看下代码注释)
<script lang="ts" setup>
import {ref, computed} from 'vue'
import {useMouseInElement} from '@vueuse/core'/*获取父组件的传值*/
defineProps<{images: string[]
}>()
// 当前显示的图片索引
let active = ref(0)
// ref 获取 DOM 元素的位置
const target = ref(null)
// isisOutside为 true 的时候代表鼠标未进入目标元素,为 false 时代表鼠标进入目标元素
const {elementX, elementY, isOutside} = useMouseInElement(target)
// 遮罩半透明图在商品大图中的坐标位置
const position = computed(() => {let x = elementX.value - 70let y = elementY.value - 70if (x <= 0) x = 0if (x >= 175) x = 175if (y <= 0) y = 0if (y >= 175) y = 175return {x, y}
})
</script>
<template><div class="product-image"><!-- 右侧的图片放大效果 --><divclass="large" :style="[{ backgroundImage: `url(${images[active]})`,backgroundPosition: `-${position.x * 2}px -${position.y * 2}px`}]" v-show="!isOutside"></div><div ref="target" class="middle"><!-- 主图 --><img :src="images[active]" alt=""/><!-- 悬浮于主图上方跟着鼠标移动的遮罩层 --><div class="layer" v-show="!isOutside" :style="{ left: `${position.x}px`, top: `${position.y}px` }"></div></div><!-- 下方的小轮播图 --><ul class="small"><li v-for="(item, index) in images" :key="item" :class="{ active: index === active }" @mouseenter="active = index"><img :src="item" alt=""/></li></ul></div>
</template><style lang="scss" scoped>
.product-image {position: relative;z-index: 500;.large {position: absolute;top: 0;left: 360px;width: 500px;height: 500px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);background-repeat: no-repeat;background-size: 170% 170%;background-color: #f8f8f8;}.middle {width: 350px;height: 350px;background: #f5f5f5;position: relative;cursor: move;.layer {width: 175px;height: 175px;background: rgba(0, 0, 0, 0.2);left: 0;top: 0;position: absolute;}img{width: 350px;height: 350px;}}.small {width: 342px;display: flex;margin-top: 5px;padding: 8px 8px;overflow-x: auto;margin-left: -8px;li {width: 64px;height: 64px;cursor: pointer;list-style: none;box-shadow: 0px 0px 8px #ccc;margin-left: 5px;img{width: 64px;height: 64px;}}}ul{margin: 0;}ul li:first-child{margin-left: 0 !important;}
}
</style>