index.vue 2.42 KB
<template>
  <div
    class="wrapper"
    ref="wrapper"
    @mousemove="mousemove"
    @mouseenter="mouseenter"
    @mouseleave="mouseleave"
    @wheel="zoom"
  >
    <transition name="fade">
      <div class="zoomed-container" v-show="isShow">
        <div
          class="transform-view"
          :style="{
            transform: `scale(${tempScale}, ${tempScale}) translate(${translateX}%, ${translateY}%)`
          }"
        >
          <img :src="url" alt="" />
        </div>
      </div>
    </transition>
    <div class="view">
      <img :src="url" alt="" />
    </div>
  </div>
</template>

<script>
import url from '@/assets/test.jpg'

export default {
  props: {
    scale: {
      type: Number,
      default: 2,
      validator: val => {
        if (val >= 1 && val <= 10) {
          return val
        } else {
          return 1
        }
      }
    }
  },
  data() {
    return {
      url,
      translateX: 0,
      translateY: 0,
      tempScale: this.scale,
      isShow: false
    }
  },
  methods: {
    zoom(e) {
      e.preventDefault()
      this.tempScale += e.deltaY * -0.01
      this.tempScale = Math.min(Math.max(1, this.tempScale), 10)
    },
    mousemove(e) {
      const {
        left,
        top,
        width,
        height
      } = this.$refs.wrapper.getBoundingClientRect()
      const x = e.clientX
      const y = e.clientY
      const percentW = (x - left) / width
      const percentH = (y - top) / height
      this.translateX = (0.4 - percentW) * 100
      this.translateY = (0.4 - percentH) * 100
    },
    mouseenter() {
      this.isShow = true
    },
    mouseleave() {
      this.isShow = false
    }
  }
}
</script>

<style lang="scss" scoped>
// 过度效果
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s;
}
.fade-enter,
.fade-leave-to {
  opacity: 0;
}
.wrapper {
  width: 400px;
  height: 357px;
  position: relative;
  overflow: hidden;
  box-sizing: border-box;
  .zoomed-container {
    background: #000;
    position: absolute;
    left: 5px;
    top: 5px;
    right: 5px;
    bottom: 5px;
    z-index: 9999;
    overflow: hidden;
    .transform-view {
      position: absolute;
      top: 0;
      left: 0;
      bottom: 0;
      right: 0;
      text-align: center;
      img {
        height: 100%;
      }
    }
  }
  .view {
    position: absolute;
    left: 5px;
    top: 5px;
    right: 5px;
    bottom: 5px;
    text-align: center;
    img {
      height: 100%;
    }
  }
}
</style>