wangrong
2026-08-30 761e5c5fa871959f60e15c971c8d83f2b53d0af5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
<script setup lang="ts">
import {
  toRefs,
  computed,
  ref,
  effectScope,
  onMounted,
  onBeforeUnmount,
  type CSSProperties
} from 'vue'
import { throttle } from 'lodash-es'
import { useEventListener } from '@vueuse/core'
const props = defineProps({
  modelValue: Boolean,
  imageUrl: String
})
 
type ImageViewerAction = 'zoomIn' | 'zoomOut' | 'clockwise' | 'anticlockwise'
 
const transform = ref({
  scale: 1
})
const scopeEventListener = effectScope()
const { modelValue, imageUrl } = toRefs(props)
const imgStyle = computed(() => {
  const { scale } = transform.value
  const style: CSSProperties = {
    transform: `scale(${scale})`
  }
  return style
})
 
const handleActions = (action: ImageViewerAction, options = {}) => {
  const { zoomRate } = {
    zoomRate: 1.4,
    ...options
  }
  switch (action) {
    case 'zoomOut':
      if (transform.value.scale > 0.2) {
        transform.value.scale = Number.parseFloat((transform.value.scale / zoomRate).toFixed(3))
      }
      break
    case 'zoomIn':
      if (transform.value.scale < 7) {
        transform.value.scale = Number.parseFloat((transform.value.scale * zoomRate).toFixed(3))
      }
      break
  }
}
 
const mousewheelHandler = throttle((e: WheelEvent | any /* TODO: wheelDelta is deprecated */) => {
  const delta = e.wheelDelta ? e.wheelDelta : -e.detail
  if (delta > 0) {
    handleActions('zoomIn', {
      zoomRate: 1.2,
      enableTransition: false
    })
  } else {
    handleActions('zoomOut', {
      zoomRate: 1.2,
      enableTransition: false
    })
  }
})
 
onMounted(() => {
  scopeEventListener.run(() => {
    useEventListener(document, 'mousewheel', mousewheelHandler)
  })
})
onBeforeUnmount(() => {
  scopeEventListener.stop()
})
const emits = defineEmits(['update:modelValue'])
const HandleBeforeClose = () => {
  transform.value.scale = 1
  modelValue.value = false
  emits('update:modelValue', false)
}
</script>
 
<template>
  <el-dialog
    class="img-enlarge-dialog"
    append-to-body
    :before-close="HandleBeforeClose"
    destroy-on-close
    close-on-click-modal
    v-model="modelValue"
  >
    <div class="img-content 13">
      <img :style="imgStyle" :src="imageUrl" alt="Preview Image" />
    </div>
  </el-dialog>
</template>
 
<style lang="less" scoped>
.img-content {
  width: 100vw;
  height: calc(100vh - 70px);
  overflow-y: hidden;
  padding: 60px 120px;
  img {
    width: 100%;
    height: 100%;
    object-fit: contain;
  }
}
</style>