Vue实现电商网站的图片放大效果

实现原理:

当鼠标移入图片区域,显示遮罩层和大图预览区
当鼠标移动,遮罩层要根据鼠标距离屏幕的坐标,动态的改变自己的距离,保证鼠标是在中心点位置
通过计算遮罩层距离屏幕的绝对距离,计算出大图应该距离屏幕的绝对距离

magnify 组件

<template>
  <div class="magnify">
    <div class="magnify-preview" @mousemove="move($event)" @mouseout="out" ref="magnifyPreview">
      <!-- 默认显示图 -->
      <img :src="previewImg" alt="">
      <!-- 移动遮罩层 -->
      <div class="preview-hover" ref="hoverBox"></div>
    </div>
    <div class="magnify-zoom" v-show="zoomVisiable" ref="magnifyZoom">
      <!-- 大预览图 -->
      <img :src="zoomImg" alt="" ref="bigImg">
    </div>
  </div>
</template>

<script>
function offset (el) {
  let top = el.offsetTop
  let left = el.offsetLeft
  while (el.offsetParent) {
    el = el.offsetParent
    top += el.offsetTop
    left += el.offsetLeft
  }
  return {
    left: left,
    top: top
  }
}
export default {
  name: 'magnify',
  props: {
    previewImg: {
      type: String,
      default: ''
    },
    zoomImg: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      zoomVisiable: false,
      hoverVisiable: false
    }
  },
  methods: {
    out () {
      this.zoomVisiable = false
    },
    move (ev) {
      this.init()
      // 鼠标距离屏幕的绝对距离
      let moveX = ev.clientX
      let moveY = ev.clientY
      // 大盒子距离屏幕的绝对距离
      let offsetLeft = offset(this.magnifyPreview).left

      let offsetTop = offset(this.magnifyPreview).top
      // left top计算出遮罩层应该距离屏幕的绝对距离
      let left = moveX - offsetLeft - this.hoverWidth / 2
      let top
      if (this.scroll > 0) {
        top = moveY - offsetTop + this.scroll - this.hoverHeight / 2
      } else {
        top = moveY - offsetTop - this.hoverHeight / 2
      }
      let maxWidth = this.pWidth - this.hoverWidth
      let maxHeight = this.pWidth - this.hoverHeight
      left = left < 0 ? 0 : left > maxWidth ? maxWidth : left
      top = top < 0 ? 0 : top > maxHeight ? maxHeight : top
      let percentX = left / (maxWidth)
      let percentY = top / (maxHeight)
      this.hoverBox.style.left = left + 'px'
      this.hoverBox.style.top = top + 'px'
      this.bigImg.style.left = percentX * (this.bWidth - this.imgWidth) + 'px'
      this.bigImg.style.top = percentY * (this.bHeight - this.imgHeight) + 'px'
      this.zoomVisiable = true
    },
    init () {
      this.hoverBox = this.$refs.hoverBox
      this.magnifyPreview = this.$refs.magnifyPreview
      this.bigImg = this.$refs.bigImg
      this.imgBox = this.$refs.magnifyZoom
      this.hoverWidth = this.hoverBox.offsetWidth
      this.hoverHeight = this.hoverBox.offsetHeight
      this.pWidth = this.magnifyPreview.offsetWidth
      this.pHeight = this.magnifyPreview.offsetHeight
      this.imgWidth = this.bigImg.offsetWidth
      this.imgHeight = this.bigImg.offsetHeight
      this.bWidth = this.imgBox.offsetWidth
      this.bHeight = this.imgBox.offsetHeight
      this.scroll = document.documentElement.scrollTop || document.body.scrollTop
    }
  }
}
</script>

<style lang="scss" scoped>
.magnify {
  position: relative;
  .magnify-preview {
    width: 480px;
    height: 480px;
    text-align: center;
    vertical-align: middle;
    border: 1px solid #dededd;
    position: relative;
    &:hover .preview-hover {
      display: block;
      visibility: visible;
    }
    .preview-hover {
      box-sizing: border-box;
      position: absolute;
      display: none;
      left: 0;
      top: 0;
      width: 240px;
      height: 240px;
      background: url("https://img-tmdetail.alicdn.com/tps/i4/T12pdtXaldXXXXXXXX-2-2.png") repeat 0 0;
      cursor: move;
      user-select: none;
    }
    img {
      max-width: 478px;
      max-height: 478px;
      display: inline-block;
    }
  }
  .magnify-zoom {
    width: 480px;
    height: 480px;
    overflow: hidden;
    position: absolute;
    left: 485px;
    border: 1px solid #dc7a7a;
    top: 0;
    img {
      position: absolute;
      top: 0;
      left: 0;
    }
  }
}
</style>

在组件中使用

<template>
  <my-magnify :previewImg="magnify.min" :zoomImg="magnify.max"></my-magnify>
</template>
<script>
  import MyMagnify from '../components/Magnify.vue'
  export default {
    data () {
      magnify: {
        min: '',
        max: ''
      },
    },
    components: {
      MyMagnify
    }
  }
</script>

效果图

posted @ 2021-09-30 15:14  wmui  阅读(346)  评论(0编辑  收藏  举报