From 093db7b37e8d2c1f358a4a404171fd8dda436bb1 Mon Sep 17 00:00:00 2001 From: neverland Date: Sun, 13 Nov 2022 11:42:26 +0800 Subject: [PATCH] feat(ImagePreview): add long-press event (#11252) * feat(ImagePreview): add long-press event * chore: upd * chore: upd * chore: upd --- .../vant/src/image-preview/ImagePreview.tsx | 5 +-- .../src/image-preview/ImagePreviewItem.tsx | 32 +++++++++++-------- packages/vant/src/image-preview/README.md | 6 ++-- .../vant/src/image-preview/README.zh-CN.md | 13 ++++---- .../vant/src/image-preview/test/index.spec.ts | 23 +++++++++++++ packages/vant/src/stepper/Stepper.tsx | 2 +- packages/vant/src/stepper/test/index.spec.ts | 5 +-- packages/vant/src/utils/constant.ts | 4 +++ 8 files changed, 62 insertions(+), 28 deletions(-) diff --git a/packages/vant/src/image-preview/ImagePreview.tsx b/packages/vant/src/image-preview/ImagePreview.tsx index db46c8824..d18c6e60b 100644 --- a/packages/vant/src/image-preview/ImagePreview.tsx +++ b/packages/vant/src/image-preview/ImagePreview.tsx @@ -77,7 +77,7 @@ export default defineComponent({ props: imagePreviewProps, - emits: ['scale', 'close', 'closed', 'change', 'update:show'], + emits: ['scale', 'close', 'closed', 'change', 'longPress', 'update:show'], setup(props, { emit, slots }) { const swipeRef = ref(); @@ -146,7 +146,7 @@ export default defineComponent({ indicatorColor="white" onChange={setActive} > - {props.images.map((image) => ( + {props.images.map((image, index) => ( emit('longPress', { index })} v-slots={{ image: slots.image, }} diff --git a/packages/vant/src/image-preview/ImagePreviewItem.tsx b/packages/vant/src/image-preview/ImagePreviewItem.tsx index a2db21706..e9680868b 100644 --- a/packages/vant/src/image-preview/ImagePreviewItem.tsx +++ b/packages/vant/src/image-preview/ImagePreviewItem.tsx @@ -14,6 +14,7 @@ import { preventDefault, createNamespace, makeRequiredProp, + LONG_PRESS_START_TIME, type ComponentInstance, } from '../utils'; @@ -45,7 +46,7 @@ export default defineComponent({ rootHeight: makeRequiredProp(Number), }, - emits: ['scale', 'close'], + emits: ['scale', 'close', 'longPress'], setup(props, { emit, slots }) { const state = reactive({ @@ -200,20 +201,23 @@ export default defineComponent({ const TAP_TIME = 250; const TAP_OFFSET = 5; - if ( - offsetX.value < TAP_OFFSET && - offsetY.value < TAP_OFFSET && - deltaTime < TAP_TIME - ) { - if (doubleTapTimer) { - clearTimeout(doubleTapTimer); - doubleTapTimer = null; - toggleScale(); - } else { - doubleTapTimer = setTimeout(() => { - emit('close'); + if (offsetX.value < TAP_OFFSET && offsetY.value < TAP_OFFSET) { + // tap or double tap + if (deltaTime < TAP_TIME) { + if (doubleTapTimer) { + clearTimeout(doubleTapTimer); doubleTapTimer = null; - }, TAP_TIME); + toggleScale(); + } else { + doubleTapTimer = setTimeout(() => { + emit('close'); + doubleTapTimer = null; + }, TAP_TIME); + } + } + // long press + else if (deltaTime > LONG_PRESS_START_TIME) { + emit('longPress'); } } }; diff --git a/packages/vant/src/image-preview/README.md b/packages/vant/src/image-preview/README.md index dbb57b284..018aefa06 100644 --- a/packages/vant/src/image-preview/README.md +++ b/packages/vant/src/image-preview/README.md @@ -235,11 +235,11 @@ Vant exports following ImagePreview utility functions: | Event | Description | Arguments | | --- | --- | --- | -| close | Emitted when closing ImagePreview | _value: { index, url }_ | +| close | Emitted when closing ImagePreview | _{ index: number, url: string }_ | | closed | Emitted when ImagePreview is closed | - | | change | Emitted when current image changed | _index: number_ | -| scale | Emitted when scaling current image | _value: ImagePreviewScaleEventParams_ | -| scale | Emitted when scaling current image | _value: ImagePreviewScaleEventParams_ | +| scale | Emitted when scaling current image | _{ index: number, scale: number }_ | +| long-press | Emitted when long press current image | _{ index: number }_ | ### Methods diff --git a/packages/vant/src/image-preview/README.zh-CN.md b/packages/vant/src/image-preview/README.zh-CN.md index 910f1706a..0e11de955 100644 --- a/packages/vant/src/image-preview/README.zh-CN.md +++ b/packages/vant/src/image-preview/README.zh-CN.md @@ -250,12 +250,13 @@ Vant 中导出了以下 ImagePreview 相关的辅助函数: 通过组件调用 `ImagePreview` 时,支持以下事件: -| 事件 | 说明 | 回调参数 | -| --- | --- | --- | -| close | 关闭时触发 | { index: 索引, url: 图片链接 } | -| closed | 关闭且且动画结束后触发 | - | -| change | 切换当前图片时触发 | index: 当前图片的索引 | -| scale | 缩放当前图片时触发 | { index: 当前图片的索引, scale: 当前缩放的值 } | +| 事件 | 说明 | 回调参数 | +| ---------- | ---------------------- | ---------------------------------- | +| close | 关闭时触发 | _{ index: number, url: string }_ | +| closed | 关闭且且动画结束后触发 | - | +| change | 切换当前图片时触发 | _index: number_ | +| scale | 缩放当前图片时触发 | _{ index: number, scale: number }_ | +| long-press | 长按当前图片时触发 | _{ index: number }_ | ### 方法 diff --git a/packages/vant/src/image-preview/test/index.spec.ts b/packages/vant/src/image-preview/test/index.spec.ts index da6151a14..dd04617c0 100644 --- a/packages/vant/src/image-preview/test/index.spec.ts +++ b/packages/vant/src/image-preview/test/index.spec.ts @@ -3,7 +3,9 @@ import { later, triggerDrag, mockGetBoundingClientRect, + trigger, } from '../../../test'; +import { LONG_PRESS_START_TIME } from '../../utils'; import ImagePreviewComponent from '../ImagePreview'; import { images, triggerZoom } from './shared'; @@ -287,3 +289,24 @@ test('should render image slot correctly 2', async () => { expect(wrapper.html().includes('video')).toBeTruthy(); }); + +test('should emit long-press event after long press', async () => { + const onLongPress = jest.fn(); + const wrapper = mount(ImagePreviewComponent, { + props: { + images, + show: true, + onLongPress, + }, + }); + + await later(); + const swipe = wrapper.find('.van-swipe-item'); + trigger(swipe, 'touchstart', 0, 0, { x: 0, y: 0 }); + await later(LONG_PRESS_START_TIME + 100); + trigger(swipe, 'touchend', 0, 0, { touchList: [] }); + + expect(onLongPress).toHaveBeenLastCalledWith({ + index: 0, + }); +}); diff --git a/packages/vant/src/stepper/Stepper.tsx b/packages/vant/src/stepper/Stepper.tsx index 5ef45ec9c..be1785876 100644 --- a/packages/vant/src/stepper/Stepper.tsx +++ b/packages/vant/src/stepper/Stepper.tsx @@ -24,6 +24,7 @@ import { callInterceptor, makeNumericProp, HAPTICS_FEEDBACK, + LONG_PRESS_START_TIME, type Numeric, } from '../utils'; @@ -33,7 +34,6 @@ import { useCustomFieldValue } from '@vant/use'; const [name, bem] = createNamespace('stepper'); const LONG_PRESS_INTERVAL = 200; -const LONG_PRESS_START_TIME = 600; const isEqual = (value1?: Numeric, value2?: Numeric) => String(value1) === String(value2); diff --git a/packages/vant/src/stepper/test/index.spec.ts b/packages/vant/src/stepper/test/index.spec.ts index de67e054f..9bdb6e5cb 100644 --- a/packages/vant/src/stepper/test/index.spec.ts +++ b/packages/vant/src/stepper/test/index.spec.ts @@ -1,6 +1,7 @@ import { nextTick } from 'vue'; import { Stepper } from '..'; import { mount, later } from '../../../test'; +import { LONG_PRESS_START_TIME } from '../../utils'; test('should disable buttons and input when using disabled prop', () => { const wrapper = mount(Stepper, { @@ -126,9 +127,9 @@ test('should update value after long pressing', async () => { expect(wrapper.emitted('update:modelValue')![0]).toEqual([2]); await plus.trigger('touchstart'); - await later(1000); + await later(LONG_PRESS_START_TIME + 500); await plus.trigger('touchend'); - expect(wrapper.emitted('update:modelValue')).toEqual([[2], [3], [4]]); + expect(wrapper.emitted('update:modelValue')).toEqual([[2], [3], [4], [5]]); }); test('should allow to disable long press', async () => { diff --git a/packages/vant/src/utils/constant.ts b/packages/vant/src/utils/constant.ts index 2904abe0c..08f92883a 100644 --- a/packages/vant/src/utils/constant.ts +++ b/packages/vant/src/utils/constant.ts @@ -12,3 +12,7 @@ export const BORDER_UNSET_TOP_BOTTOM = `${BORDER}-unset--top-bottom`; export const HAPTICS_FEEDBACK = 'van-haptics-feedback'; export const FORM_KEY: InjectionKey = Symbol('van-form'); + +// Same as the default value of iOS long press time +// https://developer.apple.com/documentation/uikit/uilongpressgesturerecognizer/1616423-minimumpressduration +export const LONG_PRESS_START_TIME = 500;