vue封装放大镜

Vue.js实现图片预览与放大镜效果,
该代码示例展示了如何在Vue项目中创建一个图片预览组件,利用鼠标位置控制图片放大效果。组件包括小图列表、鼠标跟随的放大镜以及图片切换功能。通过`useMouseInElement`插件获取鼠标位置,并动态调整蒙版和大图的显示位置。

```javascript

//使用:

1、引用

import Magnifier from '@/components/Magnifier/index.vue'

2、使用  (传递参数为 imageList :图片列表)

<Magnifier class="myMagnifier"  :imageList="list"></Magnifier>

<script setup>
//导入鼠标位置控制插件
import { useMouseInElement } from '@vueuse/core'
import {ref,watch} from 'vue'
const props=defineProps({
  imageList: {
    type: Array,
  
  },
});
//定义当前index
const activeIndex=ref(0)
//小图片位置:
const smallPosi=ref(0)
//点击图片切换index
const changeIndex=(i)=>{
    activeIndex.value=i
    //更改小图片位置:
    if(activeIndex.value>=props.imageList.length-4){
      smallPosi.value=-100*(props.imageList.length-4)
    }else{
      smallPosi.value=-100*activeIndex.value
    }
   
}
//引用
const target = ref(null)
//获取鼠标相对位置(X,Y)和是否离开目标区域
const { elementX, elementY, isOutside } = useMouseInElement(target)
//控制鼠标跟随图片移动,(鼠标移动,mask的位置发生变化)
//mask位置
const left=ref(0)
const top= ref(0)
//放大镜中图片显示位置:
const positionX = ref(0)
const positionY = ref(0)
//当鼠标位置elementX, elementY, isOutside发生改变时:
watch([ elementX, elementY, isOutside ],()=>{
    // 如果鼠标没有移入到盒子里面 直接不执行后面的逻辑
    if(isOutside.value) return
    //鼠标进入到盒子中,开始执行计算:
    if(elementX.value>100&&elementX.value<300){
        left.value=elementX.value-100
    } 
    if(elementY.value>100&&elementY.value<300){
        top.value=elementY.value-100
    }
    // 处理边界
    if (elementX.value > 300) { left.value = 200 }
    if (elementX.value < 100) { left.value = 0 }
    if (elementY.value > 300) { top.value = 200 }
    if (elementY.value < 100) { top.value = 0 }
    // 控制大图的显示位置
    positionX.value = -left.value * 2
    positionY.value = -top.value * 2
})


//点击按钮切换小图片位置:
const upView=()=>{
  if( smallPosi.value>=0){
    return
  }
  
  smallPosi.value=smallPosi.value+100
}
const dowmView=()=>{
  
  if(smallPosi.value<=-100*(props.imageList.length-4)){
    return
  }
  smallPosi.value=smallPosi.value-100
}
</script>

<template>
  <div class="goods-image">
    <!-- 左侧-->
    <div class="left">
      <div class="main" ref="target">
        <img :src="imageList[activeIndex]" alt="" />
        <!-- 蒙层小滑块 -->
        <div class="mask" :style="{ left: `${left}px`, top: `${top}px` }"></div>
      </div>
      <!-- 小图列表 -->
      <div class="small" >
        <span class="up" @click="upView"><el-icon><ArrowUp /></el-icon></span>
        <ul :style="{ top: `${smallPosi}px`,transition:`0.5s` }">
          <li v-for="(img, i) in imageList" :key="i" @click="changeIndex(i)"   :class="{active:i===activeIndex}">
            <img :src="img" alt="" />
          </li>
        </ul>
        <span class="down" @click="dowmView"><el-icon><ArrowDown /></el-icon></span>
      </div>
    </div>
    <!--  右侧 放大镜 -->
    <div class="right" :style="[
      {
        backgroundImage: `url(${imageList[activeIndex]})`,
        backgroundPositionX: `${positionX}px`,
        backgroundPositionY: `${positionY}px`,
      },
    ]" v-show="!isOutside">

    </div>
  </div>
</template>

<style scoped lang="scss">
*{
  box-sizing: border-box;
}
.goods-image{
  position: relative;
  .left{
    width: 510px;
    height: 400px;
    display: flex;
    .main{
      width: 400px;
      height: 400px;
      position: relative;
      img{
        width: 400px;
        height: 400px;
      }
      .mask{
        width: 200px;
        height: 200px;
        position:absolute;
        z-index: 1;
        background: rgba(0, 0, 0, 0.2);
        left: 0;
        top: 0;
      }
    }
    .small{
      position: relative;
      width: 100px;
      height: 400px;
      margin-left: 10px;
      overflow: hidden;
      .up,.down{
          text-align: center;
          height: 10px;
          width: 30px;
          margin-top: 0px;
          border: 1px solid darkmagenta;
          background-color: darkkhaki;
          font-size: 10px;
          z-index: 2;
          position: absolute;
          left: 50%;
          transform: translateX(-50%);
        }
        .up{
          top: 0;
          
        }
        .down{
          bottom: 0;
        }
      ul{
        width: 100px;
        position: absolute;
        height: 400px;
      
      
        li{
            width: 100px;
            height: 100px;
          img{
            width: 100%;
            height: 100%;
          }
        }
      }
    }
  }
  .right{
    width: 400px;
    height: 400px;
    background-color: pink;
    position: absolute;
    top: 0;
    left: 520px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    z-index: 99;
  }
}
.active {
  border: 2px solid darkorange;
}
</style>

### 商品放大镜组件的实现思路 在 Vue2 中实现类似京东的商品图片放大镜效果,主要通过监听鼠标事件(`mouseenter`、`mouseleave` 和 `mousemove`)来控制放大镜的显示与隐藏,并通过计算鼠标位置来调整放大镜的视口区域。组件需要包含两个部分:原图区域和放大镜区域。 - **原图区域**:用于展示商品的原始图片,鼠标在该区域移动时触发放大效果。 - **放大镜区域**:用于展示放大后的图片,通常通过 `background-image` 或 `img` 标签来实现。 ### 组件实现步骤 #### 1. 组件模板 组件模板中包含商品图片的容器和放大镜的容器,其中放大镜可以使用 `div` 或 `img` 来实现。 ```html <template> <div class="goods-preview"> <!-- 原图区域 --> <div class="goods" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave" @mousemove="handleMouseMove" > <img :src="productImage" alt="商品图片" /> <!-- 鼠标悬停区域 --> <div v-if="showMask" class="mask" :style="maskStyle"></div> </div> <!-- 放大镜区域 --> <div v-if="showBig" class="big" :style="bigStyle"> <img :src="productImage" alt="放大图片" /> </div> </div> </template> ``` #### 2. 组件数据与计算属性 组件中需要定义一些数据和计算属性,用于控制放大镜的显示和位置。 ```javascript <script> export default { props: { productImage: { type: String, required: true } }, data() { return { showMask: false, showBig: false, maskPosition: { x: 0, y: 0 }, zoomFactor: 2 // 放大倍数 }; }, computed: { maskStyle() { return { left: `${this.maskPosition.x}px`, top: `${this.maskPosition.y}px` }; }, bigStyle() { const left = -this.maskPosition.x * this.zoomFactor; const top = -this.maskPosition.y * this.zoomFactor; return { display: 'block', left: '100%', top: 0, backgroundImage: `url(${this.productImage})`, backgroundPosition: `${left}px ${top}px`, backgroundSize: `${this.zoomFactor * 100}% auto` }; } }, methods: { handleMouseEnter() { this.showMask = true; this.showBig = true; }, handleMouseLeave() { this.showMask = false; this.showBig = false; }, handleMouseMove(event) { const goodsRect = event.currentTarget.getBoundingClientRect(); const x = event.clientX - goodsRect.left; const y = event.clientY - goodsRect.top; // 控制 mask 的移动范围 const maskSize = 50; // mask 的大小 const maxX = goodsRect.width - maskSize; const maxY = goodsRect.height - maskSize; this.maskPosition.x = Math.min(Math.max(x - maskSize / 2, 0), maxX); this.maskPosition.y = Math.min(Math.max(y - maskSize / 2, 0), maxY); } } }; </script> ``` #### 3. 组件样式 样式部分需要定义商品图片容器、mask 区域和放大镜区域的布局。 ```css <style scoped> .goods-preview { position: relative; display: inline-block; } .goods { position: relative; display: inline-block; overflow: hidden; } .goods img { width: 100%; height: auto; } .mask { position: absolute; width: 50px; height: 50px; background-color: rgba(255, 255, 255, 0.3); border: 1px solid #ccc; cursor: move; } .big { position: absolute; width: 300px; height: 300px; overflow: hidden; border: 1px solid #ccc; background-repeat: no-repeat; } </style> ``` ### 使用组件 在父组件中使用该放大镜组件时,只需要传递商品图片的 URL 即可。 ```html <template> <div> <GoodsZoom :productImage="productImageUrl" /> </div> </template> <script> import GoodsZoom from './components/GoodsZoom.vue'; export default { components: { GoodsZoom }, data() { return { productImageUrl: 'https://imgres.crsky.com/crsky/60/297162-20210421095209607f8549bd770.jpg' }; } }; </script> ``` ### 功能扩展 1. **支持触摸设备**:可以通过添加 `touchstart`、`touchmove` 和 `touchend` 事件来支持移动端设备。 2. **动态调整放大倍数**:可以通过 props 传递 `zoomFactor`,让用户自定义放大倍数。 3. **支持多张图片切换**:可以在组件中添加图片切换功能,实现多图放大效果。 ### 优势 - **封装性**:将放大镜功能封装为一个独立的组件,便于复用和维护。 - **可定制性**:通过 props 和样式,可以灵活调整放大镜的大小、放大倍数等参数。 - **兼容性**:支持 PC 和移动端设备,提供良好的用户体验。 通过以上步骤,可以在 Vue2 中实现一个功能完整且可复用的商品图片放大镜组件。[^1]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值