1.完整效果
鼠标悬浮高亮放大效果
2.图片列表数据结构:
bash
detailImageList = ref(
[ "https://cbu01.alicdn.com/img/ibank/O1CN016gFMNi24tEw82w8Vj_!!2219410837448-0-cib.jpg",
"https://cbu01.alicdn.com/img/ibank/O1CN01NAgFiA24tEw82xPXg_!!2219410837448-0-cib.jpg",
"https://cbu01.alicdn.com/img/ibank/O1CN01IAJq2y24tEw9W58Aq_!!2219410837448-0-cib.jpg",
"https://cbu01.alicdn.com/img/ibank/O1CN01q5OSs924tEw94lFy4_!!2219410837448-0-cib.jpg",
"https://cbu01.alicdn.com/img/ibank/O1CN01Vdf7c724tEwP8ZJJH_!!2219410837448-0-cib.jpg",
"https://cbu01.alicdn.com/img/ibank/O1CN01ahOP1b24tEw6wZOYj_!!2219410837448-0-cib.jpg",
"https://cbu01.alicdn.com/img/ibank/O1CN012V5iiu24tEwFwpJlG_!!2219410837448-0-cib.jpg",
"https://cbu01.alicdn.com/img/ibank/O1CN01CvsVnL24tEwBgBsNs_!!2219410837448-0-cib.jpg",
"https://cbu01.alicdn.com/img/ibank/O1CN01eTsNsN24tEwJIQpmI_!!2219410837448-0-cib.jpg",
"https://cbu01.alicdn.com/img/ibank/O1CN01WD14h024tEwFwssI2_!!2219410837448-0-cib.jpg",
"https://cbu01.alicdn.com/img/ibank/O1CN01kYSj9w24tEwJLNqds_!!2219410837448-0-cib.jpg",
"https://p16-oec-general-useast5.ttcdn-us.com/tos-useast5-i-omjb5zjo8w-tx/65c2c4429b734178b096f3fb787cd092~tplv-fhlh96nyum-resize-webp:800:800.webp"
]
)
3.视图层
ts
<div v-if="detailImageList.length" class="card detail-section">
<div class="detail-section__head">
<div class="detail-section__icon detail-section__icon--primary">
<Icon icon="ep:picture" />
</div>
<div>
<div class="section-title">商品图片</div>
<div class="section-desc">共 {{ detailImageList.length }} 张图片</div>
</div>
</div>
<div class="detail-gallery">
<el-link v-for="(image, index) in detailImageList"
:key="`${selectedRecord.productId || 'image'}-${index}`" :href="detailUrl" target="_blank"
class="detail-gallery__item detail-gallery__item--clickable">
<single-image :src="image" />
</el-link>
</div>
</div>
4.样式(css)
css
.card {
border-radius: 10px;
padding: 16px;
border: 1px solid var(--el-border-color-lighter);
background: var(--el-bg-color);
box-shadow: 0 1px 2px rgb(0 0 0 / 4%);
}
.detail-section {
display: flex;
flex-direction: column;
gap: 14px;
padding: 20px;
border-radius: 12px;
border: 1px solid var(--el-border-color-lighter);
background: var(--el-bg-color);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
.detail-section__head {
display: flex;
align-items: center;
gap: 12px;
padding-bottom: 12px;
border-bottom: 1px solid var(--el-border-color-lighter);
}
.detail-section__icon {
width: 36px;
height: 36px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 16px;
}
.detail-section__icon--primary {
background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
box-shadow: 0 3px 8px rgba(64, 158, 255, 0.3);
}
.detail-section__icon--warning {
background: linear-gradient(135deg, #e6a23c 0%, #f0c278 100%);
box-shadow: 0 3px 8px rgba(230, 162, 60, 0.3);
}
.detail-section__icon--success {
background: linear-gradient(135deg, #67c23a 0%, #85ce61 100%);
box-shadow: 0 3px 8px rgba(103, 194, 58, 0.3);
}
.section-title {
font-size: 16px;
font-weight: 650;
color: var(--el-text-color-primary);
line-height: 1.4;
}
.section-desc {
margin-top: 2px;
font-size: 12px;
color: var(--el-text-color-secondary);
}
.detail-gallery {
display: flex;
flex-wrap: wrap;
gap: 14px;
align-items: flex-start;
}
.detail-gallery__item {
width: 140px;
height: 140px;
overflow: hidden;
border-radius: 10px;
border: 1px solid var(--el-border-color-lighter);
background: var(--el-fill-color-lighter);
}
.detail-gallery__item--clickable {
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
&:hover {
transform: scale(1.03);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
border-color: var(--el-color-primary-light-5);
}
}
.detail-gallery__item--clickable :deep(.el-link) {
text-decoration: none;
}
.detail-gallery__item :deep(img) {
object-fit: cover;
width: 100%;
height: 100%;
}
5.图片组件封装如下
ts
<template>
<el-image
v-bind="$attrs"
style="width: 120px; min-height: 80px; object-fit: contain"
:src="src"
class="cursor-pointer"
referrerpolicy="no-referrer"
@click="doPreview(src)"
>
<template #placeholder>
<div class="img-loading" style="min-width: 120px; min-height: 120px"></div>
</template>
<template #error>
<div
class="flex items-center justify-center w-full h-full"
style="color: red; min-height: 80px"
>
加载失败
</div>
</template>
</el-image>
</template>
<script setup>
import { api as viewerApi } from "v-viewer";
const props = defineProps({
src: {
type: String,
default: "",
},
});
async function doPreview(url) {
viewerApi({
images: [url],
options: {
zIndex: 4000,
toolbar: {
flipHorizontal: {
show: true,
},
flipVertical: {
show: true,
},
next: {
show: false,
},
oneToOne: {
show: true,
},
play: {
show: false,
},
prev: {
show: false,
},
reset: {
show: true,
},
rotateLeft: {
show: true,
},
rotateRight: {
show: true,
},
zoomIn: {
show: true,
},
zoomOut: {
show: true,
},
},
},
});
}
</script>
<style>
.img-loading {
width: 100%;
height: 100%;
list-style: none;
background-image: linear-gradient(100deg, #fafafa 25%, #eaeaea 37%, #fafafa 63%);
background-size: 400% 100%;
background-position: 100% 50%;
animation: skeleton-loading 1.4s ease infinite;
}
@keyframes skeleton-loading {
0% {
background-position: 100% 50%;
}
100% {
background-position: 0 50%;
}
}
</style>
icon
快捷 方便 好用 推荐!
