1
+ <template >
2
+ <Transition name =" fade" @after-leave =" onDestroy" >
3
+ <div v-show =" visible" class =" img-view" :style =" [{zIndex: zIndex}]" @mousewheel =" handleMouseWheel($event)" >
4
+ <div style =" position : absolute ;z-index : 2 ;top : 20px ;color : red ;width : 100% ;text-align : center ;" >组件未引入框架,请自己在组件内修改相关icon(改完这条删)</div >
5
+ <div class =" view-btn set-close fcc" @click =" onClose" title =" 关闭" >×</div >
6
+ <div v-show =" imgIndex > 0" class =" view-btn set-pre fcc" @click =" onPre" title =" 上一张" >←</div >
7
+ <div v-show =" imgIndex < imgList.length - 1" class =" view-btn set-next fcc" @click =" onNext" title =" 下一张" >→</div >
8
+ <div class =" view-set fcc" >
9
+ <span class =" set-item" @click =" handleImgSet('enlarge')" title =" 缩小" >-</span >
10
+ <span class =" set-item" @click =" handleImgSet('narrow')" title =" 放大" >+</span >
11
+ <span class =" set-item" @click =" handleImgSet('recovery')" title =" 恢复" >口</span >
12
+ <span class =" set-item" @click =" handleImgSet('turnLeft')" title =" 左转" >↪</span >
13
+ <span class =" set-item" @click =" handleImgSet('turnRight')" title =" 右转" >↩</span >
14
+ </div >
15
+ <div class =" img-box" >
16
+ <img
17
+ class =" img-content"
18
+ :style =" [{transform: `scale(${imgStyle.scale}) rotate(${imgStyle.rotate}deg)`, marginTop: imgStyle.marginTop + 'px', marginLeft: imgStyle.marginLeft + 'px', transition: `all ${imgStyle.tranistionTime}s linear`}]"
19
+ :src =" imgSrc.url"
20
+ @dragstart.prevent
21
+ @mousedown =" handleMouseDown($event)"
22
+ @mousemove =" handleMouseMove($event)"
23
+ @mouseup =" handleMouseUp($event)"
24
+ @mouseleave =" handleMouseUp($event)"
25
+ >
26
+ </div >
27
+ </div >
28
+ </Transition >
29
+
30
+ </template >
31
+ <script setup lang='ts'>
32
+ import { ImgContent } from " ./main"
33
+ import { ref , reactive , onMounted , onBeforeUnmount , defineProps , defineEmits , computed } from ' vue'
34
+ const props = defineProps ({
35
+ imgList: {// 图片列表
36
+ type: Array < ImgContent > ,
37
+ default: []
38
+ },
39
+ index: {// 图片显示下标
40
+ type: Number ,
41
+ default: 0 ,
42
+ },
43
+ zIndex: {// 层级
44
+ type: Number ,
45
+ default: 1000 ,
46
+ }
47
+ })
48
+ const emit = defineEmits ([' destroy' ])
49
+ const visible = ref (false )
50
+ const imgIndex = ref (props .index )
51
+ const imgStyle = reactive ({
52
+ tranistionTime: 0.2 ,
53
+ scale: 1 ,
54
+ rotate: 0 ,
55
+ marginTop: 0 ,
56
+ marginLeft: 0 ,
57
+ startX: 0 ,
58
+ startY: 0 ,
59
+ })
60
+ const imgSrc = computed (() => props .imgList [imgIndex .value ])
61
+ onMounted (() => {
62
+ visible .value = true
63
+ document .addEventListener (' keydown' , handleKeyDown )
64
+ })
65
+ onBeforeUnmount (() => {
66
+ document .removeEventListener (' keydown' , handleKeyDown )
67
+ })
68
+ function handleKeyDown (e : KeyboardEvent ) {
69
+ switch (e .code ) {
70
+ case ' Escape' :
71
+ onClose ()
72
+ break ;
73
+ case ' ArrowLeft' :
74
+ onPre ()
75
+ break ;
76
+ case ' ArrowRight' :
77
+ onNext ()
78
+ break ;
79
+ case ' ArrowUp' :
80
+ handleImgSet (' narrow' )
81
+ break ;
82
+ case ' ArrowDown' :
83
+ handleImgSet (' enlarge' )
84
+ break ;
85
+ case ' Enter' :
86
+ handleImgSet (' recovery' )
87
+ break ;
88
+ default :
89
+ break ;
90
+ }
91
+ }
92
+ // 按钮操作
93
+ function onClose () {// 关闭
94
+ visible .value = false
95
+ }
96
+ function onPre () {// 上一张
97
+ if (imgIndex .value > 0 ) {
98
+ imgStyle .scale = 1
99
+ imgIndex .value --
100
+ }
101
+ }
102
+ function onNext () {// 下一张
103
+ if (imgIndex .value < props .imgList .length - 1 ) {
104
+ imgStyle .scale = 1
105
+ imgIndex .value ++
106
+ }
107
+ }
108
+ function handleImgSet (set : String ) {// 图片操作
109
+ if (set == ' enlarge' ) {
110
+ imgStyle .scale = imgStyle .scale - 0.1
111
+ } else if (set == ' narrow' ) {
112
+ imgStyle .scale = imgStyle .scale + 0.1
113
+ } else if (set == ' recovery' ) {
114
+ imgStyle .scale = 1
115
+ imgStyle .rotate = 0
116
+ imgStyle .marginTop = 0
117
+ imgStyle .marginLeft = 0
118
+ imgStyle .startX = 0
119
+ imgStyle .startY = 0
120
+ } else if (set == ' turnLeft' ) {
121
+ imgStyle .rotate = imgStyle .rotate - 90
122
+ } else if (set == ' turnRight' ) {
123
+ imgStyle .rotate = imgStyle .rotate + 90
124
+ }
125
+ }
126
+ // 拖拽处理
127
+ const isPressed = ref (false )
128
+ function handleMouseDown (e : MouseEvent ) {
129
+ isPressed .value = true
130
+ imgStyle .tranistionTime = 0
131
+ imgStyle .startX = e .pageX - imgStyle .marginLeft / 2
132
+ imgStyle .startY = e .pageY - imgStyle .marginTop / 2
133
+ }
134
+ function handleMouseMove (e : MouseEvent ) {
135
+ if (isPressed .value ) {
136
+ imgStyle .marginLeft = (e .pageX - imgStyle .startX ) * 2
137
+ imgStyle .marginTop = (e .pageY - imgStyle .startY ) * 2
138
+ }
139
+ }
140
+ function handleMouseUp (e : MouseEvent ) {
141
+ isPressed .value = false
142
+ imgStyle .tranistionTime = 0.2
143
+ imgStyle .startX = 0
144
+ imgStyle .startY = 0
145
+ }
146
+ // 鼠标滚轮
147
+ function handleMouseWheel (e : WheelEvent ) {
148
+ const scaleVal = imgStyle .scale - e .deltaY / 5000
149
+ if (scaleVal > 0.1 && scaleVal < 3 ) {
150
+ imgStyle .scale = scaleVal
151
+ }
152
+ }
153
+ // 动画结束销毁
154
+ function onDestroy () {
155
+ emit (' destroy' )
156
+ }
157
+ </script >
158
+
159
+ <style >
160
+ .img-view {
161
+ position : fixed ;
162
+ top : 0 ;
163
+ left : 0 ;
164
+ bottom : 0 ;
165
+ right : 0 ;
166
+ background-color : rgba (0 , 0 , 0 , 0.5 );
167
+ }
168
+ .set-close {
169
+ position : absolute ;
170
+ top : 40px ;
171
+ right : 40px ;
172
+ }
173
+ .set-pre {
174
+ position : absolute ;
175
+ left : 40px ;
176
+ top : 50% ;
177
+ transform : rotateY (-50% );
178
+ }
179
+ .set-next {
180
+ position : absolute ;
181
+ right : 40px ;
182
+ top : 50% ;
183
+ transform : rotateY (-50% );
184
+ }
185
+ .view-btn {
186
+ width : 40px ;
187
+ height : 40px ;
188
+ border-radius : 50% ;
189
+ background-color : #606266 ;
190
+ color : #fff ;
191
+ cursor : pointer ;
192
+ user-select : none ;
193
+ font-size : 25px ;
194
+ z-index : 2 ;
195
+ }
196
+ .view-set {
197
+ position : absolute ;
198
+ bottom : 40px ;
199
+ left : 50% ;
200
+ transform : translateX (-50% );
201
+ background-color : #606266 ;
202
+ color : #fff ;
203
+ cursor : pointer ;
204
+ user-select : none ;
205
+ z-index : 2 ;
206
+ border-radius : 50px ;
207
+ }
208
+ .set-item {
209
+ padding : 10px 15px ;
210
+ font-size : 20px ;
211
+ }
212
+ .set-item :first-child {
213
+ border-radius : 50px 0px 0px 50px ;
214
+ padding : 10px 15px 10px 20px ;
215
+ }
216
+ .set-item :last-child {
217
+ border-radius : 0px 50px 50px 0px ;
218
+ padding : 10px 20px 10px 15px ;
219
+ }
220
+ .img-box {
221
+ width : 100% ;
222
+ height : 100% ;
223
+ display : flex ;
224
+ align-items : center ;
225
+ justify-content : center ;
226
+ }
227
+ .img-content {
228
+ user-select : none ;
229
+ display : block ;
230
+ content : " " ;
231
+ max-width : 100% ;
232
+ max-height : 100% ;
233
+ }
234
+ .fcc {
235
+ display : flex ;
236
+ align-items : center ;
237
+ justify-content : center ;
238
+ }
239
+ .fade-enter-from , .fade-leave-to {
240
+ opacity : 0 ;
241
+ }
242
+ .fade-enter-active ,.fade-leave-active {
243
+ transition : all .3s cubic-bezier (.55 ,0 ,.1 ,1 );
244
+ }
245
+ </style >
0 commit comments