From d67031a98d90cb0b02670165f5a1ceb3007f23e4 Mon Sep 17 00:00:00 2001 From: neverland Date: Fri, 19 Feb 2021 17:16:07 +0800 Subject: [PATCH] types(ImagePreview): use tsx (#8176) --- .../{ImagePreview.js => ImagePreview.tsx} | 36 ++++++----- ...agePreviewItem.js => ImagePreviewItem.tsx} | 63 +++++++++++-------- src/image-preview/{index.js => index.tsx} | 50 +++++++++++---- src/image-preview/shared.js | 5 -- src/vue-tsx-shim.d.ts | 5 ++ 5 files changed, 102 insertions(+), 57 deletions(-) rename src/image-preview/{ImagePreview.js => ImagePreview.tsx} (83%) rename src/image-preview/{ImagePreviewItem.js => ImagePreviewItem.tsx} (83%) rename src/image-preview/{index.js => index.tsx} (50%) delete mode 100644 src/image-preview/shared.js diff --git a/src/image-preview/ImagePreview.js b/src/image-preview/ImagePreview.tsx similarity index 83% rename from src/image-preview/ImagePreview.js rename to src/image-preview/ImagePreview.tsx index e1dca377f..88b159255 100644 --- a/src/image-preview/ImagePreview.js +++ b/src/image-preview/ImagePreview.tsx @@ -1,9 +1,8 @@ -import { nextTick, onMounted, reactive, ref, watch } from 'vue'; +import { nextTick, onMounted, PropType, reactive, ref, watch } from 'vue'; // Utils -import { UnknownProp } from '../utils'; -import { bem, createComponent } from './shared'; -import { callInterceptor } from '../utils/interceptor'; +import { ComponentInstance, UnknownProp, createNamespace } from '../utils'; +import { callInterceptor, Interceptor } from '../utils/interceptor'; // Composition import { useWindowSize } from '@vant/use'; @@ -11,19 +10,21 @@ import { useExpose } from '../composables/use-expose'; // Components import Icon from '../icon'; -import Swipe from '../swipe'; -import Popup from '../popup'; +import Swipe, { SwipeToOptions } from '../swipe'; +import Popup, { PopupCloseIconPosition } from '../popup'; import ImagePreviewItem from './ImagePreviewItem'; +const [createComponent, bem] = createNamespace('image-preview'); + export default createComponent({ props: { show: Boolean, closeable: Boolean, className: UnknownProp, - beforeClose: Function, + beforeClose: Function as PropType, showIndicators: Boolean, images: { - type: Array, + type: Array as PropType, default: () => [], }, loop: { @@ -63,7 +64,7 @@ export default createComponent({ default: true, }, closeIconPosition: { - type: String, + type: String as PropType, default: 'top-right', }, }, @@ -71,7 +72,7 @@ export default createComponent({ emits: ['scale', 'close', 'closed', 'change', 'update:show'], setup(props, { emit, slots }) { - const swipeRef = ref(); + const swipeRef = ref(); const windowSize = useWindowSize(); const state = reactive({ @@ -89,11 +90,11 @@ export default createComponent({ } }; - const emitScale = (args) => { + const emitScale = (args: { scale: number; index: number }) => { emit('scale', args); }; - const toggle = (show) => { + const toggle = (show: boolean) => { emit('update:show', show); }; @@ -107,7 +108,7 @@ export default createComponent({ }); }; - const setActive = (active) => { + const setActive = (active: number) => { if (active !== state.active) { state.active = active; emit('change', active); @@ -177,7 +178,7 @@ export default createComponent({ emit('closed'); }; - const swipeTo = (index, options) => { + const swipeTo = (index: number, options?: SwipeToOptions) => { if (swipeRef.value) { swipeRef.value.swipeTo(index, options); } @@ -189,7 +190,12 @@ export default createComponent({ watch([windowSize.width, windowSize.height], resize); - watch(() => props.startPosition, setActive); + watch( + () => props.startPosition, + (value) => { + setActive(+value); + } + ); watch( () => props.show, diff --git a/src/image-preview/ImagePreviewItem.js b/src/image-preview/ImagePreviewItem.tsx similarity index 83% rename from src/image-preview/ImagePreviewItem.js rename to src/image-preview/ImagePreviewItem.tsx index 9bc00f044..2b19f9232 100644 --- a/src/image-preview/ImagePreviewItem.js +++ b/src/image-preview/ImagePreviewItem.tsx @@ -1,8 +1,7 @@ -import { watch, computed, reactive } from 'vue'; +import { watch, computed, reactive, CSSProperties, defineComponent } from 'vue'; // Utils -import { bem } from './shared'; -import { range, preventDefault } from '../utils'; +import { range, preventDefault, createNamespace } from '../utils'; // Composition import { useTouch } from '../composables/use-touch'; @@ -12,22 +11,36 @@ import Image from '../image'; import Loading from '../loading'; import SwipeItem from '../swipe-item'; -function getDistance(touches) { +function getDistance(touches: TouchList) { return Math.sqrt( (touches[0].clientX - touches[1].clientX) ** 2 + (touches[0].clientY - touches[1].clientY) ** 2 ); } -export default { +const bem = createNamespace('image-preview')[1]; + +export default defineComponent({ props: { src: String, show: Boolean, active: Number, - minZoom: [Number, String], - maxZoom: [Number, String], - rootWidth: Number, - rootHeight: Number, + minZoom: { + type: [Number, String], + required: true, + }, + maxZoom: { + type: [Number, String], + required: true, + }, + rootWidth: { + type: Number, + required: true, + }, + rootHeight: { + type: Number, + required: true, + }, }, emits: ['scale', 'close'], @@ -54,7 +67,7 @@ export default { const imageStyle = computed(() => { const { scale, moveX, moveY, moving, zooming } = state; - const style = { + const style: CSSProperties = { transitionDuration: zooming || moving ? '0s' : '.3s', }; @@ -93,7 +106,7 @@ export default { return 0; }); - const setScale = (scale) => { + const setScale = (scale: number) => { scale = range(scale, +props.minZoom, +props.maxZoom); if (scale !== state.scale) { @@ -119,14 +132,14 @@ export default { state.moveY = 0; }; - let startMoveX; - let startMoveY; - let startScale; - let startDistance; - let doubleTapTimer; - let touchStartTime; + let startMoveX: number; + let startMoveY: number; + let startScale: number; + let startDistance: number; + let doubleTapTimer: NodeJS.Timeout | null; + let touchStartTime: number; - const onTouchStart = (event) => { + const onTouchStart = (event: TouchEvent) => { const { touches } = event; const { offsetX } = touch; @@ -134,7 +147,7 @@ export default { startMoveX = state.moveX; startMoveY = state.moveY; - touchStartTime = new Date(); + touchStartTime = Date.now(); state.moving = touches.length === 1 && state.scale !== 1; state.zooming = touches.length === 2 && !offsetX.value; @@ -145,7 +158,7 @@ export default { } }; - const onTouchMove = (event) => { + const onTouchMove = (event: TouchEvent) => { const { touches } = event; touch.move(event); @@ -172,7 +185,7 @@ export default { const checkTap = () => { const { offsetX, offsetY } = touch; - const deltaTime = new Date() - touchStartTime; + const deltaTime = Date.now() - touchStartTime; const TAP_TIME = 250; const TAP_OFFSET = 10; @@ -194,7 +207,7 @@ export default { } }; - const onTouchEnd = (event) => { + const onTouchEnd = (event: TouchEvent) => { let stopPropagation = false; /* istanbul ignore else */ @@ -234,8 +247,8 @@ export default { touch.reset(); }; - const onLoad = (event) => { - const { naturalWidth, naturalHeight } = event.target; + const onLoad = (event: Event) => { + const { naturalWidth, naturalHeight } = event.target as HTMLImageElement; state.imageRatio = naturalHeight / naturalWidth; }; @@ -274,4 +287,4 @@ export default { ); }; }, -}; +}); diff --git a/src/image-preview/index.js b/src/image-preview/index.tsx similarity index 50% rename from src/image-preview/index.js rename to src/image-preview/index.tsx index b83aec2ce..01d286b45 100644 --- a/src/image-preview/index.js +++ b/src/image-preview/index.tsx @@ -1,23 +1,47 @@ -import { inBrowser } from '../utils'; +import { App, TeleportProps } from 'vue'; +import { ComponentInstance, inBrowser } from '../utils'; import { mountComponent, usePopupState } from '../utils/mount-component'; +import { Interceptor } from '../utils/interceptor'; +import { PopupCloseIconPosition } from '../popup'; import VanImagePreview from './ImagePreview'; -let instance; +let instance: ComponentInstance; -const defaultConfig = { +export type ImagePreviewOptions = { + loop?: boolean; + images: string[]; + maxZoom?: number; + minZoom?: number; + teleport?: TeleportProps['to']; + className?: unknown; + showIndex?: boolean; + closeable?: boolean; + closeIcon?: string; + beforeClose?: Interceptor; + swipeDuration?: number; + startPosition?: number; + showIndicators?: boolean; + closeOnPopstate?: boolean; + closeIconPosition?: PopupCloseIconPosition; + onClose?(): void; + onScale?(args: { scale: number; index: number }): void; + onChange?(index: number): void; +}; + +const defaultConfig: ImagePreviewOptions = { loop: true, images: [], maxZoom: 3, minZoom: 1 / 3, - onScale: null, - onClose: null, - onChange: null, + onScale: undefined, + onClose: undefined, + onChange: undefined, teleport: 'body', className: '', showIndex: true, closeable: false, closeIcon: 'clear', - beforeClose: null, + beforeClose: undefined, startPosition: 0, swipeDuration: 300, showIndicators: false, @@ -29,9 +53,8 @@ function initInstance() { ({ instance } = mountComponent({ setup() { const { state, toggle } = usePopupState(); - const onClosed = () => { - state.images = []; + (state as any).images = []; }; return () => ( @@ -47,7 +70,10 @@ function initInstance() { })); } -const ImagePreview = (images, startPosition = 0) => { +const ImagePreview = ( + images: string[] | ImagePreviewOptions, + startPosition = 0 +) => { /* istanbul ignore if */ if (!inBrowser) { return; @@ -69,8 +95,8 @@ const ImagePreview = (images, startPosition = 0) => { ImagePreview.Component = VanImagePreview; -ImagePreview.install = (app) => { - app.use(VanImagePreview); +ImagePreview.install = (app: App) => { + app.use(VanImagePreview as any); }; export default ImagePreview; diff --git a/src/image-preview/shared.js b/src/image-preview/shared.js deleted file mode 100644 index c3e8e5ba8..000000000 --- a/src/image-preview/shared.js +++ /dev/null @@ -1,5 +0,0 @@ -import { createNamespace } from '../utils'; - -const [createComponent, bem] = createNamespace('image-preview'); - -export { createComponent, bem }; diff --git a/src/vue-tsx-shim.d.ts b/src/vue-tsx-shim.d.ts index 38f08abe6..546357ef7 100644 --- a/src/vue-tsx-shim.d.ts +++ b/src/vue-tsx-shim.d.ts @@ -12,11 +12,13 @@ declare module 'vue' { onBlur?: EventHandler; onOpen?: EventHandler; onEdit?: EventHandler; + onLoad?: EventHandler; onClose?: EventHandler; onFocus?: EventHandler; onInput?: EventHandler; onClick?: EventHandler; onPress?: EventHandler; + onScale?: EventHandler; onCancel?: EventHandler; onOpened?: EventHandler; onClosed?: EventHandler; @@ -26,7 +28,10 @@ declare module 'vue' { onToggle?: EventHandler; onConfirm?: EventHandler; onKeypress?: EventHandler; + onTouchend?: EventHandler; onClickStep?: EventHandler; + onTouchmove?: EventHandler; onTouchstart?: EventHandler; + onTouchcancel?: EventHandler; } }