vue中如何实现图片放大镜功能

vue中图片放大镜功能

1、在vue项目中不可避免的会做一个图片放大镜的弄能(例如、商城、店铺等),今天同事问了这个功能恰好以前写过,因此记录一下。

2、废话不多说直接上代码:

父组件中:


<template>
  <div>
    <imgZoom class="imgZoom" v-if="imgpic" :url="imgpic" :highUrl="imgpic"></imgZoom>
  </div>
</template>
<script>
import imgZoom from '@/components/imgZoom.vue'
export default {
  data() {
    return {
      imgpic: null
    };
  },
components: {
    imgZoom
  },
}
</script>
<style>
.imgZoom {
    width: 400px;
    height: 400px;
}

</style>

子组件部分:

<template>
  <div class="pic-img">
    <div class="img-container" @mousemove="!moveEvent && mouseMove($event)" @mouseleave="!leaveEvent && mouseLeave($event)">
      <img ref="img" @load="imgLoaded" :src="url" style="width:400px" />
      <div
        v-if="!hideZoom && imgLoadedFlag"
        :class="['img-selector', { circle: type === 'circle' }]"
        :style="[imgSelectorSize, imgSelectorPosition, !outShow && imgSelectorBg, !outShow && imgBgPosition]"
      ></div>
      <div v-if="outShow" v-show="!hideOutShow" class="img-out-show" :style="[imgOutShowSize, imgSelectorBg, imgBgPosition]"></div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'vue-photo-zoom-pro',
  data() {
    return {
      selector: {
        width: 166,
        halfWidth: 83,
        top: 0,
        left: 0,
        bgTop: 0,
        bgLeft: 0,
        rightBound: 0,
        bottomBound: 0,
        absoluteLeft: 0,
        absoluteTop: 0
      },
      imgInfo: {},
      hideOutShow: true,
      imgLoadedFlag: false,
      screenWidth: document.body.clientWidth,
      timer: null
      // url: '../static/img/zz.jpg',
      // highUrl: '../static/img/zz.jpg'
    }
  },
  props: {
    url: String,
    highUrl: String,
    type: {
      type: String,
      default: 'square',
      validator: function(value) {
        return ['circle', 'square'].indexOf(value) !== -1
      }
    },
    scale: {
      type: Number,
      default: 2
    },
    moveEvent: {
      type: [Object, MouseEvent],
      default: null
    },
    leaveEvent: {
      type: [Object, MouseEvent],
      default: null
    },
    hideZoom: {
      type: Boolean,
      default: false
    },
    outShow: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    moveEvent(e) {
      this.mouseMove(e)
    },
    leaveEvent(e) {
      this.mouseLeave(e)
    },
    url() {
      this.imgLoadedFlag = false
    },
    screenWidth(val) {
      if (!this.timer) {
        this.screenWidth = val
        this.timer = setTimeout(() => {
          this.imgLoaded()
          clearTimeout(this.timer)
          this.timer = null
        }, 400)
      }
    }
  },
  computed: {
    imgSelectorPosition() {
      let { top, left } = this.selector
      return {
        top: `${top}px`,
        left: `${left}px`
      }
    },
    imgSelectorSize() {
      let width = this.selector.width
      return {
        width: `${width}px`,
        height: `${width}px`
      }
    },
    imgOutShowSize() {
      let {
        scale,
        selector: { width }
      } = this
      return {
        width: `${width * scale}px`,
        height: `${width * scale}px`
      }
    },
    imgSelectorBg() {
      let {
        scale,
        url,
        highUrl,
        imgInfo: { height, width }
      } = this
      return {
        backgroundImage: `url(${highUrl || url})`,
        backgroundSize: `${width * scale}px ${height * scale}px`
      }
    },
    imgBgPosition() {
      let { bgLeft, bgTop } = this.selector
      return {
        backgroundPosition: `${bgLeft}px ${bgTop}px`
      }
    }
  },
  methods: {
    imgLoaded() {
      let imgInfo = this.$refs['img'].getBoundingClientRect()
      if (JSON.stringify(this.imgInfo) == JSON.stringify(imgInfo)) {
        // 位置不变不更新
        return
      }
      this.imgLoadedFlag = true
      let { width, height, left, top } = (this.imgInfo = imgInfo)
      let selector = this.selector
      let { width: selectorWidth, halfWidth: selectorHalfWidth } = selector
      let { scrollLeft, scrollTop } = document.documentElement
      selector.rightBound = width - selectorWidth
      selector.bottomBound = height - selectorWidth
      selector.absoluteLeft = left + selectorHalfWidth + scrollLeft
      selector.absoluteTop = top + selectorHalfWidth + scrollTop
    },
    reset() {
      Object.assign(this.selector, {
        top: 0,
        left: 0,
        bgLeft: 0,
        bgTop: 0
      })
    },
    mouseMove(e) {
      if (!this.hideZoom && this.imgLoadedFlag) {
        this.imgLoaded() //防止img位置变化
        let { pageX, pageY } = e
        let { scale, selector } = this
        let { halfWidth, absoluteLeft, absoluteTop, rightBound, bottomBound } = selector
        let x = pageX - absoluteLeft // 选择器的x坐标 相对于图片
        let y = pageY - absoluteTop // 选择器的y坐标
        if (this.outShow) {
          halfWidth = 0
          this.hideOutShow = false
        }
        selector.top = y > 0 ? (y < bottomBound ? y : bottomBound) : 0
        selector.left = x > 0 ? (x < rightBound ? x : rightBound) : 0
        selector.bgLeft = halfWidth - (halfWidth + x) * scale // 选择器图片的坐标位置
        selector.bgTop = halfWidth - (halfWidth + y) * scale
      }
    },
    mouseLeave() {
      if (this.outShow) {
        this.hideOutShow = true
      }
    }
  }
}
</script>
<style scoped>
.img-container {
  position: relative;
}

.img-selector {
  background-color: rgba(0, 0, 0, 0.6);
  position: absolute;
  background-repeat: no-repeat;
  cursor: crosshair;
  border: 1px solid rgba(0, 0, 0, 0.1);
}

.img-selector.circle {
  border-radius: 50%;
}

.img-out-show {
  position: absolute;
  top: 0;
  right: 0;
  background-repeat: no-repeat;
  transform: translate(100%, 0);
  border: 1px solid rgba(0, 0, 0, 0.1);
}
</style>

备注:

:url="imgpic" 

:highUrl="imgpic"

两个表示需要展示和放大的图片,需统一

(此方法非原创,但是时间有点久了忘记在那个地方看到的!作者看见勿怪)

实现淘宝图片放大镜功能,可以通过以下步骤实现: 1. 在 Vue 组件引入所需的依赖库,例如 `element-ui` 等。 2. 在模板,将需要实现放大镜效果的图片绑定到一个 `<div>` 元素上,并设置其样式。 3. 在该 `<div>` 元素上绑定 `@mousemove` 事件,监听鼠标在该元素上的移动。 4. 在事件处理函数,获取鼠标在元素上的坐标,并根据元素的大小和图片的大小计算出放大镜的位置。 5. 使用 `element-ui` 的 `Dialog` 组件,将放大的图片作为弹出框的内容,并设置其样式,并在需要放大的图片上绑定 `@click` 事件,当点击该图片时,弹出放大镜。 下面是一个简单的 Vue 组件示例代码: ```html <template> <div class="image-container" @mousemove="handleMouseMove"> <img src="./image.jpg" alt="image" class="image" @click="showDialog"> <el-dialog :visible.sync="dialogVisible" width="60%"> <img src="./image.jpg" alt="image" class="dialog-image"> </el-dialog> </div> </template> <script> export default { data() { return { dialogVisible: false, zoomedImageStyle: { position: 'absolute', border: '1px solid #ccc', width: '200px', height: '200px', display: 'none', zIndex: 9999 } } }, methods: { handleMouseMove(e) { const { clientX, clientY } = e const { left, top, width, height } = e.target.getBoundingClientRect() const x = clientX - left const y = clientY - top const zoomedImage = document.querySelector('.zoomed-image') const percentageX = x / width const percentageY = y / height const imageWidth = zoomedImage.width const imageHeight = zoomedImage.height const leftOffset = -percentageX * (imageWidth - width) const topOffset = -percentageY * (imageHeight - height) this.zoomedImageStyle.display = 'block' this.zoomedImageStyle.left = `${x}px` this.zoomedImageStyle.top = `${y}px` this.zoomedImageStyle.backgroundImage = `url(${zoomedImage.src})` this.zoomedImageStyle.backgroundSize = `${imageWidth}px ${imageHeight}px` this.zoomedImageStyle.backgroundPositionX = `${leftOffset}px` this.zoomedImageStyle.backgroundPositionY = `${topOffset}px` }, showDialog() { this.dialogVisible = true } } } </script> <style> .image-container { position: relative; } .image { width: 100%; height: auto; } .dialog-image { width: 100%; height: auto; } .zoomed-image { position: absolute; border: 1px solid #ccc; width: 200px; height: 200px; display: none; z-index: 9999; } </style> ``` 在该示例代码,通过绑定 `@mousemove` 事件,监听鼠标在元素上的移动,并在事件处理函数计算出放大镜的位置,然后通过设置 `zoomedImageStyle` 对象的属性来实现放大镜。同时,在需要放大的图片上绑定 `@click` 事件,当用户点击该图片时,弹出包含放大图片的 `Dialog` 对话框。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值