plain-design 1.0.0-beta.30 → 1.0.0-beta.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/plain-design.commonjs.min.js +3 -3
  2. package/dist/plain-design.min.css +11 -6
  3. package/dist/plain-design.min.js +3 -3
  4. package/dist/report.html +2 -2
  5. package/package.json +3 -3
  6. package/src/packages/components/$previewer/ImagePreviewerFixedContainer.tsx +107 -0
  7. package/src/packages/components/$previewer/image-previewer-fixed-container.scss +18 -0
  8. package/src/packages/components/$previewer/index.tsx +52 -0
  9. package/src/packages/components/Application/service/useApplicationService.tsx +2 -0
  10. package/src/packages/components/Carousel/carousel.scss +391 -0
  11. package/src/packages/components/Carousel/index.tsx +569 -22
  12. package/src/packages/components/CarouselItem/index.tsx +77 -0
  13. package/src/packages/components/ImagePreviewer/ImagePreviewer.tsx +572 -0
  14. package/src/packages/components/ImagePreviewer/ImagePreviewerButtonBar.tsx +140 -0
  15. package/src/packages/components/ImagePreviewer/ImagePreviewerCarouselImage.tsx +54 -0
  16. package/src/packages/components/ImagePreviewer/ImagePreviewerGallery.tsx +202 -0
  17. package/src/packages/components/ImagePreviewer/PreviewerLoading.tsx +26 -0
  18. package/src/packages/components/ImagePreviewer/image-previewer.scss +244 -0
  19. package/src/packages/components/ImagePreviewer/image-previewer.utils.tsx +135 -0
  20. package/src/packages/components/ImagePreviewer/index.tsx +5 -0
  21. package/src/packages/components/ImagePreviewer/previewer-loading.scss +52 -0
  22. package/src/packages/components/Input/useMultipleInput.tsx +2 -79
  23. package/src/packages/components/InputNumber/NumberResize.tsx +14 -1
  24. package/src/packages/components/InputNumber/input-number.utils.tsx +7 -5
  25. package/src/packages/components/InputNumber/useInputNumber.public.tsx +25 -6
  26. package/src/packages/components/Scroll/index.tsx +6 -6
  27. package/src/packages/components/SortList/index.tsx +191 -0
  28. package/src/packages/components/SortList/sort-list.scss +11 -0
  29. package/src/packages/components/StackCard/index.tsx +260 -0
  30. package/src/packages/components/StackCard/stack-card.scss +28 -0
  31. package/src/packages/components/StackCardItem/index.tsx +23 -0
  32. package/src/packages/components/Table/standard/PlcOperation/PlcOperation.tsx +1 -1
  33. package/src/packages/components/Table/standard/PlcTree/RenderPlcTreeNode.tsx +2 -1
  34. package/src/packages/components/Table/table/body/row.tsx +1 -1
  35. package/src/packages/components/Table/table/use/useTableDraggier.row.tsx +1 -1
  36. package/src/packages/components/Table/table/utils/createTableHooks.ts +1 -1
  37. package/src/packages/components/Tree/RenderTreeNode.tsx +2 -1
  38. package/src/packages/components/Tree/index.tsx +2 -1
  39. package/src/packages/components/VirtualList/index.tsx +12 -3
  40. package/src/packages/components/VirtualList/useVirtualList.tsx +129 -86
  41. package/src/packages/components/VirtualList/virtual-list.scss +31 -17
  42. package/src/packages/components/VirtualTable/index.tsx +1 -1
  43. package/src/packages/entry.tsx +5 -1
  44. package/src/packages/uses/useDragHorizontalScroll.ts +82 -0
  45. package/src/packages/utils/ComponentUtils.ts +10 -0
  46. package/src/packages/utils/buildCycleIndexList.ts +31 -0
  47. package/src/packages/utils/getDeviceInfo.ts +44 -44
  48. package/src/packages/utils/getRectAutoFormat.ts +9 -0
  49. package/src/packages/utils/notNull.ts +9 -0
  50. package/src/pages/index/app.scss +1 -1
  51. package/src/pages/index/components/normal/DemoCarousel.tsx +178 -73
  52. package/src/pages/index/components/normal/DemoKeepAlive.tsx +25 -25
  53. package/src/pages/index/components/normal/DemoNumber.tsx +4 -1
  54. package/src/pages/index/components/normal/DemoSortList.tsx +70 -0
  55. package/src/pages/index/components/normal/DemoStackCard.tsx +356 -0
  56. package/src/pages/index/components/normal/DemoVirtualList.tsx +89 -3
  57. package/src/pages/index/components/service/DemoImagePreviewer.tsx +185 -0
  58. package/src/pages/index/home/AppHome.tsx +18 -3
  59. package/src/pages/index/home/menus.tsx +3 -1
  60. package/src/packages/components/CarouselGroup/carousel.scss +0 -143
  61. package/src/packages/components/CarouselGroup/index.tsx +0 -274
@@ -0,0 +1,572 @@
1
+ import {computed, designComponent, iHTMLDivElement, onBeforeUnmount, onMounted, PropType, reactive, useClasses, useRefs, useStyles} from "plain-design-composition";
2
+ import {getCenterRect, iImagePreviewerOption, ImagePreviewerHooks} from "./image-previewer.utils";
3
+ import {createEffects} from "plain-utils/utils/createEffects";
4
+ import {getRectAutoFormat} from "../../utils/getRectAutoFormat";
5
+ import {addElementListener} from "plain-utils/dom/addElementListener";
6
+ import {delay} from "plain-utils/utils/delay";
7
+ import Carousel from "../Carousel";
8
+ import CarouselItem from "../CarouselItem";
9
+ import {ImagePreviewerGallery} from "./ImagePreviewerGallery";
10
+ import {ImagePreviewerCarouselImage} from "./ImagePreviewerCarouselImage";
11
+ import './image-previewer.scss';
12
+ import {ImagePreviewerButtonBar} from "./ImagePreviewerButtonBar";
13
+ import {addWindowListener} from "plain-utils/dom/addWindowListener";
14
+ import $previewer from "../$previewer";
15
+ import {buildCycleIndexList} from "../../utils/buildCycleIndexList";
16
+ import {getDeviceInfo} from "../../utils/getDeviceInfo";
17
+
18
+ export const ImagePreviewer = designComponent({
19
+ name: 'image-preview-component',
20
+ props: {
21
+ option: { type: Object as PropType<iImagePreviewerOption>, required: true }
22
+ },
23
+ inheritPropsType: iHTMLDivElement,
24
+ setup({ props }) {
25
+
26
+ const { effects: setupEffects } = createEffects();
27
+
28
+ const { refs, onRef } = useRefs({ el: iHTMLDivElement, carousel: Carousel });
29
+
30
+ const state = reactive({
31
+ /*当前显示的图片索引*/
32
+ current: props.option.current || 0,
33
+ /*shadowImageElement显示隐藏有过度时间,这里等过度时间结束再做显示隐藏*/
34
+ show: false,
35
+ aspectRatio: null as null | number,
36
+ closing: false,
37
+ /*标记图片的thumb url已经加载完毕*/
38
+ readyMap: {} as Record<string, boolean | undefined>
39
+ });
40
+
41
+ const classes = useClasses(() => [
42
+ 'image-previewer-component',
43
+ {
44
+ 'image-previewer-component-waiting': !state.show
45
+ }
46
+ ]);
47
+
48
+ const galleryStyles = useStyles(style => {
49
+ style.height = `${props.option.galleryHeight}px`;
50
+ });
51
+
52
+ const maskStyles = useStyles(style => {
53
+ style.backgroundColor = props.option.maskColor || 'rgba(0,0,0,0.9)';
54
+ });
55
+
56
+ const methods = {
57
+ /**
58
+ * 关闭预览
59
+ * @author 韦胜健
60
+ * @date 2024/1/5 11:24
61
+ */
62
+ close: async () => {
63
+ if (state.closing) {return;}
64
+ state.closing = true;
65
+
66
+ const currentImgElement = refs.carousel!.refs.el!.querySelector('img[data-active=true]') as undefined | HTMLImageElement;
67
+ /*当前渲染的图片如果不存在,虽然不可能,这里直接关闭previewer*/
68
+ if (!currentImgElement) {
69
+ $previewer.close(props.option.id);
70
+ return;
71
+ }
72
+
73
+ /*当前正在显示的图片元素,关闭时让这个元素显示一个缩小动画*/
74
+ const sourceImgElement = props.option.imageElement;
75
+
76
+ const currentRect = getCenterRect({ imageElement: currentImgElement, containerElement: refs.carousel!.refs.el! });
77
+
78
+ /*页面上原始的图片元素如果存在,则让当前显示的图片元素缩放并且移动到这个原始位置在关闭,否则移动到屏幕正中间在关闭*/
79
+ const sourceRect = !!sourceImgElement ? getRectAutoFormat(sourceImgElement) : (() => {
80
+ const { clientHeight, clientWidth } = document.documentElement;
81
+ const width = 10;
82
+ const height = 10;
83
+ const top = Number(((clientHeight - height) / 2).toFixed(2));
84
+ const left = Number(((clientWidth - width) / 2).toFixed(2));
85
+ return { top, left, width, height };
86
+ })();
87
+
88
+ currentImgElement.style.transition = 'all ease 300ms';
89
+ const newScale = Number(((sourceRect.width / currentRect.width)).toFixed(2));
90
+ const newLeft = Math.ceil(sourceRect.left - (currentRect.left + (currentRect.width * (1 - newScale) / 2)));
91
+ const newTop = Math.ceil(sourceRect.top - (currentRect.top + (currentRect.height * (1 - newScale) / 2)));
92
+ // console.log({ sourceRect, currentRect, newTop, newLeft });
93
+ state.show = false;
94
+ const clearListener = addElementListener(currentImgElement, 'transitionend', () => {
95
+ clearListener();
96
+ if (!!props.option?.imageElement) {
97
+ props.option.imageElement.style.opacity = '';
98
+ }
99
+ $previewer.close(props.option.id);
100
+ });
101
+ await delay(0);
102
+ currentImgElement.style.transform = `translate3d(${newLeft}px,${newTop}px,0) scale(${newScale}) rotate(0)`;
103
+ },
104
+ /**
105
+ * 切换到上一张
106
+ * @author 韦胜健
107
+ * @date 2024/1/8 17:35
108
+ */
109
+ prev: () => {
110
+ let current = state.current - 1;
111
+ if (current < 0) {
112
+ current = props.option.urls.length - 1;
113
+ }
114
+ state.current = current;
115
+ },
116
+ /**
117
+ * 切换到下一张
118
+ * @author 韦胜健
119
+ * @date 2024/1/8 17:35
120
+ */
121
+ next: () => {
122
+ let current = state.current + 1;
123
+ if (current > props.option.urls.length - 1) {
124
+ current = 0;
125
+ }
126
+ state.current = current;
127
+ },
128
+ };
129
+
130
+ const handler = {
131
+ onDoubleClickImage: () => {
132
+ methods.close();
133
+ },
134
+ onChangeCurrent: () => {
135
+ transformHandler.transformMethods.reset();
136
+ if (!!props.option.imageElement) {
137
+ if (props.option.imageElement.style.opacity != props.option.oldSourceImageOpacity) {
138
+ props.option.imageElement.style.opacity = props.option.oldSourceImageOpacity || "";
139
+ }
140
+ }
141
+ }
142
+ };
143
+
144
+ const transformHandler = (() => {
145
+ const transformState = reactive({
146
+ transformData: {
147
+ /*当前缩放的比例*/
148
+ scale: 1,
149
+ /*当前横向移动距离*/
150
+ left: 0,
151
+ /*当前纵向移动距离*/
152
+ top: 0,
153
+ /*当前旋转角度*/
154
+ rotate: 0,
155
+ },
156
+ /*保存开始缩放时当前image的初始大小*/
157
+ currentImageRect: { top: 0, left: 0, height: 0, width: 0 },
158
+ /*是否处于移动端缩小准备退出的状态*/
159
+ mobileClosing: false,
160
+ /*双指缩放状态*/
161
+ mobileScaling: null as null | {
162
+ startScale: number,/*双指拖拽开始时已经缩放的大小*/
163
+ msg?: any,/*调试信息*/
164
+ },
165
+ previousTouchstartTimestamp: 0,
166
+ });
167
+
168
+ const handler = {
169
+ /**
170
+ * 使用鼠标滚轮的时候设置缩放比例
171
+ * @author 韦胜健
172
+ * @date 2024/1/5 14:20
173
+ */
174
+ onWheel: (e: WheelEvent) => {
175
+ if (props.option.disableZoomOnWheel) {
176
+ return;
177
+ }
178
+ e.stopPropagation();
179
+ e.preventDefault();
180
+ transformMethods.setScale(Number((transformState.transformData.scale - e.deltaY / 100 * 0.05).toFixed(2)));
181
+ },
182
+ /**
183
+ * 拖拽的时候处理移动或者缩放
184
+ * @author 韦胜健
185
+ * @date 2024/1/5 14:21
186
+ */
187
+ touchstart: (e: TouchEvent | MouseEvent) => {
188
+
189
+ if ('touches' in e && e.touches.length == 1 && getDeviceInfo().deviceType === 'mobile') {
190
+ const currentTouchstartTimestamp = Date.now();
191
+ if (!!transformState.previousTouchstartTimestamp) {
192
+ if (currentTouchstartTimestamp - transformState.previousTouchstartTimestamp < 200) {
193
+ /*100ms内点击了两次,自动关闭*/
194
+ methods.close();
195
+ return;
196
+ }
197
+ }
198
+ transformState.previousTouchstartTimestamp = currentTouchstartTimestamp;
199
+ }
200
+
201
+ /*标记当前是缩放还是移动*/
202
+ let handleType = 'move' as 'scale' | 'move';
203
+
204
+ /*拖拽副作用*/
205
+ const { effects: touchEffects } = createEffects();
206
+
207
+ /**
208
+ * 单指和双指会同时触发touchstart,这里除了双指缩放之外的其他情况要自动停止并且清理掉自身的副作用
209
+ * @author 韦胜健
210
+ * @date 2024/1/9 21:42
211
+ */
212
+ const autoClearIfDoubleTouching = (e: MouseEvent | TouchEvent) => {
213
+ if ('touches' in e && e.touches.length === 2) {
214
+ touchEffects.clear();
215
+ return true;
216
+ }
217
+ return false;
218
+ };
219
+
220
+ if ('touches' in e && e.touches.length > 1) {
221
+ /*如果是双指拖动,则为缩放,否则都是移动*/
222
+ handleType = 'scale';
223
+ }
224
+
225
+ if (handleType === 'move') {
226
+ /*只有缩放/旋转的情况下才能拖拽移动,否则拖拽时右Carousel处理横向切换图片*/
227
+ if (isTransforming.value) {
228
+ /*---------------------------------------(单指/鼠标)拖拽移动-------------------------------------------*/
229
+
230
+ /*拖拽初始状态*/
231
+ let touchState = {
232
+ startX: 'touches' in e ? e.touches[0].clientX : e.clientX,
233
+ startY: 'touches' in e ? e.touches[0].clientY : e.clientY,
234
+ startTop: transformState.transformData.top,
235
+ startLeft: transformState.transformData.left,
236
+ };
237
+ /*处理移动*/
238
+ const touchmove = (e: MouseEvent | TouchEvent) => {
239
+ if (autoClearIfDoubleTouching(e)) {return;}
240
+ e.preventDefault();
241
+ e.stopPropagation();
242
+ const moveX = 'touches' in e ? e.touches[0].clientX : e.clientX;
243
+ const moveY = 'touches' in e ? e.touches[0].clientY : e.clientY;
244
+ transformState.transformData.top = Number((touchState.startTop + (moveY - touchState.startY)).toFixed(2));
245
+ transformState.transformData.left = Number((touchState.startLeft + (moveX - touchState.startX)).toFixed(2));
246
+ };
247
+ touchEffects.push(addElementListener(document.body, 'touchmove', touchmove, { passive: false }));
248
+ touchEffects.push(addElementListener(document.body, 'touchend', touchEffects.clear, { passive: false }));
249
+ touchEffects.push(addElementListener(document.body, 'mousemove', touchmove, { passive: false }));
250
+ touchEffects.push(addElementListener(document.body, 'mouseup', touchEffects.clear, { passive: false }));
251
+ } else {
252
+ if (getDeviceInfo().deviceType === 'mobile' && 'touches' in e && e.touches.length === 1) {
253
+
254
+ /*---------------------------------------单指拖拽关闭-------------------------------------------*/
255
+
256
+ /*移动端的情况下,如果纵向移动超过一定距离,则一边移动一边缩小,缩小到一定程度关闭预览*/
257
+ let imageElement = (e.currentTarget as HTMLDivElement).querySelector('img') as HTMLImageElement;
258
+ let mobileTouchState = {
259
+ startX: e.touches[0].clientX,
260
+ startY: e.touches[0].clientY,
261
+ touching: null as null | { scale: number },
262
+ };
263
+ const touchmove = (e: TouchEvent) => {
264
+ if (autoClearIfDoubleTouching(e)) {return;}
265
+ e.stopPropagation();
266
+ e.preventDefault();
267
+ let durX = e.touches[0].clientX - mobileTouchState.startX;
268
+ let durY = e.touches[0].clientY - mobileTouchState.startY;
269
+ if (!mobileTouchState.touching) {
270
+ if (durY > durX && durY > 10) {
271
+ transformState.mobileClosing = true;
272
+ mobileTouchState.touching = { scale: 1 };
273
+ /*拖拽结束时的处理动作*/
274
+ touchEffects.push(async () => {
275
+ transformState.mobileClosing = false;
276
+
277
+ if (mobileTouchState.touching!.scale < 0.9) {
278
+ /*取消缩放,改为实际设置大小,是的关闭动画合理*/
279
+ methods.close();
280
+ } else {
281
+ /*取消缩放,还原原来的状态*/
282
+ imageElement.style.transition = "all ease 300ms";
283
+ imageElement.style.transform = "translate3d(0,0,0) scale(1)";
284
+ delay(300).then(() => {
285
+ imageElement.style.transition = "";
286
+ imageElement.style.transform = "";
287
+ });
288
+ }
289
+
290
+ mobileTouchState.touching = null;
291
+ });
292
+ }
293
+ }
294
+ if (!mobileTouchState.touching) {
295
+ return;
296
+ }
297
+ if (durY < 0) {durY = 0;}
298
+ if (durY === 0) {
299
+ /*移动距离为0,不做缩放移动*/
300
+ imageElement.style.transform = '';
301
+ } else {
302
+ /*按照移动距离进行缩放移动*/
303
+ const height = Math.ceil(document.body.clientHeight / 3);
304
+ const scale = Number((1 - durY / height).toFixed(2));
305
+ mobileTouchState.touching.scale = scale;
306
+ imageElement.style.transform = `translate3d(0,${durY}px,0) scale(${scale})`;
307
+ }
308
+ };
309
+ touchEffects.push(addElementListener(document.body, 'touchmove', touchmove, { passive: false }));
310
+ touchEffects.push(addElementListener(document.body, 'touchend', touchEffects.clear, { passive: false }));
311
+ }
312
+ }
313
+
314
+ } else {
315
+ /*---------------------------------------双指拖拽缩放-------------------------------------------*/
316
+
317
+ if (!('touches' in e)) {return;}
318
+ const startTouchesDistance = Math.floor(Math.sqrt(Math.pow((e.touches[1].clientX - e.touches[0].clientX), 2) + Math.pow((e.touches[1].clientY - e.touches[0].clientY), 2)));
319
+
320
+ transformState.mobileScaling = { startScale: transformState.transformData.scale };
321
+
322
+ const touchmove = (e: TouchEvent) => {
323
+ e.stopPropagation();
324
+ e.preventDefault();
325
+
326
+ const moveTouchesDistance = Math.floor(Math.sqrt(Math.pow((e.touches[1].clientX - e.touches[0].clientX), 2) + Math.pow((e.touches[1].clientY - e.touches[0].clientY), 2)));
327
+ const durationDistance = Math.floor(moveTouchesDistance - startTouchesDistance);
328
+ const durScale = Number((durationDistance / 300).toFixed(2));
329
+ let newScale = Number((durScale + transformState.mobileScaling!.startScale).toFixed(2));
330
+ if (newScale < 1) {
331
+ newScale = 1;
332
+ }
333
+ transformMethods.setScale(newScale);
334
+ transformState.mobileScaling!.msg = `newScale:${newScale}`;
335
+ };
336
+
337
+ touchEffects.push(() => {
338
+ transformState.mobileScaling = null;
339
+ });
340
+
341
+ touchEffects.push(addElementListener(document.body, 'touchmove', touchmove, { passive: false, }));
342
+ touchEffects.push(addElementListener(document.body, 'touchend', touchEffects.clear, { passive: false }));
343
+ }
344
+ },
345
+ };
346
+
347
+ const transformStyles = useStyles(style => {
348
+ let left = transformState.transformData.left;
349
+ let top = transformState.transformData.top;
350
+
351
+ if (transformState.transformData.scale != 1) {
352
+
353
+ /**
354
+ * 限制位置不能超过边界
355
+ * @author 韦胜健
356
+ * @date 2024/1/5 15:47
357
+ */
358
+
359
+ let { clientHeight, clientWidth } = refs.carousel!.refs.el!;
360
+
361
+ const currentWidth = Number((transformState.currentImageRect.width * transformState.transformData.scale).toFixed(0));
362
+ const currentHeight = Number((transformState.currentImageRect.height * transformState.transformData.scale).toFixed(0));
363
+
364
+ if (currentWidth > clientWidth) {
365
+ const overWidth = Number(((currentWidth - clientWidth) / 2).toFixed(2));
366
+ if (left < -overWidth) {
367
+ left = -overWidth;
368
+ }
369
+ if (left > overWidth) {
370
+ left = overWidth;
371
+ }
372
+ } else {
373
+ left = 0;
374
+ }
375
+
376
+ if (currentHeight > clientHeight) {
377
+ const overHeight = Number(((currentHeight - clientHeight) / 2).toFixed(2));
378
+ if (top < -overHeight) {
379
+ top = -overHeight;
380
+ }
381
+ if (top > overHeight) {
382
+ top = overHeight;
383
+ }
384
+ } else {
385
+ top = 0;
386
+ }
387
+ }
388
+
389
+ style.transform = `translate3d(${left}px,${top}px,0) scale(${transformState.transformData.scale}) rotate(${transformState.transformData.rotate}deg)`;
390
+ });
391
+
392
+ const isTransforming = computed(() => !!transformState.mobileClosing || !!transformState.mobileScaling || transformState.transformData.scale != 1 || transformState.transformData.top != 0 || transformState.transformData.left != 0 || transformState.transformData.rotate != 0);
393
+
394
+ const transformMethods = {
395
+ zoomIn: () => {
396
+ transformMethods.setScale(Number((transformState.transformData.scale + 0.25).toFixed(1)));
397
+ },
398
+ zoomOut: () => {
399
+ transformMethods.setScale(Number((transformState.transformData.scale - 0.25).toFixed(1)));
400
+ },
401
+ anticlockwise: () => {
402
+ transformState.transformData.rotate = Number((transformState.transformData.rotate - 45).toFixed(1));
403
+ },
404
+ clockwise: () => {
405
+ transformState.transformData.rotate = Number((transformState.transformData.rotate + 45).toFixed(1));
406
+ },
407
+ /**
408
+ * 设置缩放比例,当比例小于1时设置为1,并且重置所有变化
409
+ * @author 韦胜健
410
+ * @date 2024/1/5 14:20
411
+ */
412
+ setScale: (val: number) => {
413
+ if (val < 1) {
414
+ val = 1;
415
+ }
416
+ if (val == transformState.transformData.scale) {
417
+ return;
418
+ }
419
+ if (transformState.transformData.scale === 1) {
420
+ /*保存图片初始的大小尺寸*/
421
+ transformState.currentImageRect = getRectAutoFormat(refs.el?.querySelector('img[data-active=true]') as HTMLImageElement);
422
+ }
423
+ if (val === 1) {
424
+ transformMethods.reset();
425
+ } else {
426
+ transformState.transformData.scale = val;
427
+ }
428
+ },
429
+ /**
430
+ * 重置所有变化
431
+ * @author 韦胜健
432
+ * @date 2024/1/5 14:20
433
+ */
434
+ reset: () => {
435
+ transformState.transformData = {
436
+ scale: 1,
437
+ left: 0,
438
+ top: 0,
439
+ rotate: 0,
440
+ };
441
+ },
442
+ };
443
+
444
+ return { transformState, handler, isTransforming, transformStyles, transformMethods };
445
+ })();
446
+
447
+ const carouselOptimizer = (() => {
448
+
449
+ /*原始索引映射到环列表,在环列表中距离当前显示的索引的距离*/
450
+ const index2distance = computed(() => {
451
+ return buildCycleIndexList({ length: props.option.urls.length, current: state.current }).index2distance;
452
+ });
453
+
454
+ const isShow = (sourceIndex: number) => Math.abs(index2distance.value[sourceIndex]) < 2;
455
+
456
+ return {
457
+ isShow
458
+ };
459
+ })();
460
+
461
+ const keyboardHandler = (() => {
462
+ let isHovering = false;
463
+ const onMousemove = () => isHovering = true;
464
+ const onMouseleave = () => isHovering = false;
465
+ const initialize = () => {
466
+ if (!props.option.globalKeyboardEvent) {
467
+ setupEffects.push(addElementListener(refs.el!, 'mousemove', onMousemove));
468
+ setupEffects.push(addElementListener(refs.el!, 'mouseleave', onMouseleave));
469
+ }
470
+ setupEffects.push(
471
+ addWindowListener('keydown', e => {
472
+ if (!props.option.globalKeyboardEvent) {
473
+ if (!isHovering) {return;}
474
+ }
475
+ if (e.keyCode === 27) {
476
+ if (props.option.button == false || (typeof props.option.button === "object" && props.option.button.close == false)) {
477
+ return;
478
+ }
479
+ methods.close();
480
+ } else if (e.keyCode === 37) {
481
+ methods.prev();
482
+ } else if (e.keyCode === 39) {
483
+ methods.next();
484
+ }
485
+ })
486
+ );
487
+ };
488
+ return {
489
+ initialize,
490
+ };
491
+ })();
492
+
493
+ onMounted(async () => {
494
+ state.aspectRatio = refs.el!.offsetWidth / refs.el!.offsetHeight;
495
+ await delay(23);
496
+ state.show = true;
497
+ setupEffects.push(addElementListener(refs.el!, 'wheel', transformHandler.handler.onWheel));
498
+ keyboardHandler.initialize();
499
+ });
500
+
501
+ onBeforeUnmount(setupEffects.clear);
502
+
503
+ return () => (
504
+ <div className={classes.value} ref={onRef.el} onDoubleClick={handler.onDoubleClickImage}>
505
+ {state.aspectRatio != null && <>
506
+ {!!props.option.mask && <div className="image-previewer-component-mask" style={maskStyles.value}/>}
507
+ <Carousel
508
+ ref={onRef.carousel}
509
+ autoPlay={0}
510
+ v-model={state.current}
511
+ height={props.option.autoHeight ? undefined : `calc(100% - ${props.option.galleryHeight}px)`}
512
+ style={{ paddingBottom: `${props.option.separatorHeight}px` }}
513
+ onChange={handler.onChangeCurrent}
514
+ disableSwiper={transformHandler.isTransforming.value}
515
+ largeSwitchButton
516
+ switchButton={props.option.swipeButton == false ? false : undefined}
517
+ nextSwitchButtonTip="下一张(右按键)"
518
+ prevSwitchButtonTip="上一张(左按键)"
519
+ >
520
+ {props.option.urls.map((item, index) => (
521
+ <CarouselItem
522
+ key={index}
523
+ val={index}
524
+ onMousedownInner={index === state.current ? transformHandler.handler.touchstart : undefined}
525
+ onTouchstartInner={index === state.current ? transformHandler.handler.touchstart : undefined}
526
+ loading={state.readyMap[item.url] !== true}
527
+ >
528
+ {carouselOptimizer.isShow(index) && (
529
+ <ImagePreviewerCarouselImage
530
+ direction={props.option.autoHeight ? 'horizontal' : undefined}
531
+ clientRatio={state.aspectRatio!}
532
+ data-active={String(index === state.current)}
533
+ src={item.url}
534
+ style={index === state.current && transformHandler.isTransforming.value ? transformHandler.transformStyles.value : undefined}
535
+ onReady={() => {
536
+ state.readyMap = {
537
+ ...state.readyMap,
538
+ [item.url]: true,
539
+ };
540
+ index === state.current && ImagePreviewerHooks.onImagePreviewerReady.exec({ option: props.option });
541
+ }}
542
+ />
543
+ )}
544
+ </CarouselItem>
545
+ ))}
546
+ </Carousel>
547
+ {props.option.gallery != false && (
548
+ <ImagePreviewerGallery
549
+ option={props.option}
550
+ v-model={state.current}
551
+ onChange={handler.onChangeCurrent}
552
+ style={galleryStyles.value}
553
+ />
554
+ )}
555
+ {props.option.button !== false && (
556
+ <ImagePreviewerButtonBar
557
+ button={props.option.button}
558
+
559
+ onZoomIn={transformHandler.transformMethods.zoomIn}
560
+ onZoomOut={transformHandler.transformMethods.zoomOut}
561
+ onAnticlockwise={transformHandler.transformMethods.anticlockwise}
562
+ onClockwise={transformHandler.transformMethods.clockwise}
563
+ onReset={transformHandler.transformMethods.reset}
564
+ onClose={methods.close}
565
+ />
566
+ )}
567
+ </>}
568
+ {/*<div style={{ position: 'fixed', top: '0', left: '0', width: '100%' }}>{JSON.stringify(transformHandler.transformState.mobileScaling)}</div>*/}
569
+ </div>
570
+ );
571
+ },
572
+ });