<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>