鼠标悬浮+高亮放大图片效果(vue)

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

icon 标签网站,快速找到需要icon

快捷 方便 好用 推荐!