Skip to content

Commit 093db7b

Browse files
authored
feat(ImagePreview): add long-press event (#11252)
* feat(ImagePreview): add long-press event * chore: upd * chore: upd * chore: upd
1 parent 839bcd8 commit 093db7b

File tree

8 files changed

+62
-28
lines changed

8 files changed

+62
-28
lines changed

packages/vant/src/image-preview/ImagePreview.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export default defineComponent({
7777

7878
props: imagePreviewProps,
7979

80-
emits: ['scale', 'close', 'closed', 'change', 'update:show'],
80+
emits: ['scale', 'close', 'closed', 'change', 'longPress', 'update:show'],
8181

8282
setup(props, { emit, slots }) {
8383
const swipeRef = ref<SwipeInstance>();
@@ -146,7 +146,7 @@ export default defineComponent({
146146
indicatorColor="white"
147147
onChange={setActive}
148148
>
149-
{props.images.map((image) => (
149+
{props.images.map((image, index) => (
150150
<ImagePreviewItem
151151
src={image}
152152
show={props.show}
@@ -157,6 +157,7 @@ export default defineComponent({
157157
rootHeight={state.rootHeight}
158158
onScale={emitScale}
159159
onClose={emitClose}
160+
onLongPress={() => emit('longPress', { index })}
160161
v-slots={{
161162
image: slots.image,
162163
}}

packages/vant/src/image-preview/ImagePreviewItem.tsx

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
preventDefault,
1515
createNamespace,
1616
makeRequiredProp,
17+
LONG_PRESS_START_TIME,
1718
type ComponentInstance,
1819
} from '../utils';
1920

@@ -45,7 +46,7 @@ export default defineComponent({
4546
rootHeight: makeRequiredProp(Number),
4647
},
4748

48-
emits: ['scale', 'close'],
49+
emits: ['scale', 'close', 'longPress'],
4950

5051
setup(props, { emit, slots }) {
5152
const state = reactive({
@@ -200,20 +201,23 @@ export default defineComponent({
200201
const TAP_TIME = 250;
201202
const TAP_OFFSET = 5;
202203

203-
if (
204-
offsetX.value < TAP_OFFSET &&
205-
offsetY.value < TAP_OFFSET &&
206-
deltaTime < TAP_TIME
207-
) {
208-
if (doubleTapTimer) {
209-
clearTimeout(doubleTapTimer);
210-
doubleTapTimer = null;
211-
toggleScale();
212-
} else {
213-
doubleTapTimer = setTimeout(() => {
214-
emit('close');
204+
if (offsetX.value < TAP_OFFSET && offsetY.value < TAP_OFFSET) {
205+
// tap or double tap
206+
if (deltaTime < TAP_TIME) {
207+
if (doubleTapTimer) {
208+
clearTimeout(doubleTapTimer);
215209
doubleTapTimer = null;
216-
}, TAP_TIME);
210+
toggleScale();
211+
} else {
212+
doubleTapTimer = setTimeout(() => {
213+
emit('close');
214+
doubleTapTimer = null;
215+
}, TAP_TIME);
216+
}
217+
}
218+
// long press
219+
else if (deltaTime > LONG_PRESS_START_TIME) {
220+
emit('longPress');
217221
}
218222
}
219223
};

packages/vant/src/image-preview/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,11 @@ Vant exports following ImagePreview utility functions:
235235

236236
| Event | Description | Arguments |
237237
| --- | --- | --- |
238-
| close | Emitted when closing ImagePreview | _value: { index, url }_ |
238+
| close | Emitted when closing ImagePreview | _{ index: number, url: string }_ |
239239
| closed | Emitted when ImagePreview is closed | - |
240240
| change | Emitted when current image changed | _index: number_ |
241-
| scale | Emitted when scaling current image | _value: ImagePreviewScaleEventParams_ |
242-
| scale | Emitted when scaling current image | _value: ImagePreviewScaleEventParams_ |
241+
| scale | Emitted when scaling current image | _{ index: number, scale: number }_ |
242+
| long-press | Emitted when long press current image | _{ index: number }_ |
243243

244244
### Methods
245245

packages/vant/src/image-preview/README.zh-CN.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -250,12 +250,13 @@ Vant 中导出了以下 ImagePreview 相关的辅助函数:
250250

251251
通过组件调用 `ImagePreview` 时,支持以下事件:
252252

253-
| 事件 | 说明 | 回调参数 |
254-
| --- | --- | --- |
255-
| close | 关闭时触发 | { index: 索引, url: 图片链接 } |
256-
| closed | 关闭且且动画结束后触发 | - |
257-
| change | 切换当前图片时触发 | index: 当前图片的索引 |
258-
| scale | 缩放当前图片时触发 | { index: 当前图片的索引, scale: 当前缩放的值 } |
253+
| 事件 | 说明 | 回调参数 |
254+
| ---------- | ---------------------- | ---------------------------------- |
255+
| close | 关闭时触发 | _{ index: number, url: string }_ |
256+
| closed | 关闭且且动画结束后触发 | - |
257+
| change | 切换当前图片时触发 | _index: number_ |
258+
| scale | 缩放当前图片时触发 | _{ index: number, scale: number }_ |
259+
| long-press | 长按当前图片时触发 | _{ index: number }_ |
259260

260261
### 方法
261262

packages/vant/src/image-preview/test/index.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import {
33
later,
44
triggerDrag,
55
mockGetBoundingClientRect,
6+
trigger,
67
} from '../../../test';
8+
import { LONG_PRESS_START_TIME } from '../../utils';
79
import ImagePreviewComponent from '../ImagePreview';
810
import { images, triggerZoom } from './shared';
911

@@ -287,3 +289,24 @@ test('should render image slot correctly 2', async () => {
287289

288290
expect(wrapper.html().includes('video')).toBeTruthy();
289291
});
292+
293+
test('should emit long-press event after long press', async () => {
294+
const onLongPress = jest.fn();
295+
const wrapper = mount(ImagePreviewComponent, {
296+
props: {
297+
images,
298+
show: true,
299+
onLongPress,
300+
},
301+
});
302+
303+
await later();
304+
const swipe = wrapper.find('.van-swipe-item');
305+
trigger(swipe, 'touchstart', 0, 0, { x: 0, y: 0 });
306+
await later(LONG_PRESS_START_TIME + 100);
307+
trigger(swipe, 'touchend', 0, 0, { touchList: [] });
308+
309+
expect(onLongPress).toHaveBeenLastCalledWith({
310+
index: 0,
311+
});
312+
});

packages/vant/src/stepper/Stepper.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
callInterceptor,
2525
makeNumericProp,
2626
HAPTICS_FEEDBACK,
27+
LONG_PRESS_START_TIME,
2728
type Numeric,
2829
} from '../utils';
2930

@@ -33,7 +34,6 @@ import { useCustomFieldValue } from '@vant/use';
3334
const [name, bem] = createNamespace('stepper');
3435

3536
const LONG_PRESS_INTERVAL = 200;
36-
const LONG_PRESS_START_TIME = 600;
3737

3838
const isEqual = (value1?: Numeric, value2?: Numeric) =>
3939
String(value1) === String(value2);

packages/vant/src/stepper/test/index.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { nextTick } from 'vue';
22
import { Stepper } from '..';
33
import { mount, later } from '../../../test';
4+
import { LONG_PRESS_START_TIME } from '../../utils';
45

56
test('should disable buttons and input when using disabled prop', () => {
67
const wrapper = mount(Stepper, {
@@ -126,9 +127,9 @@ test('should update value after long pressing', async () => {
126127
expect(wrapper.emitted('update:modelValue')![0]).toEqual([2]);
127128

128129
await plus.trigger('touchstart');
129-
await later(1000);
130+
await later(LONG_PRESS_START_TIME + 500);
130131
await plus.trigger('touchend');
131-
expect(wrapper.emitted('update:modelValue')).toEqual([[2], [3], [4]]);
132+
expect(wrapper.emitted('update:modelValue')).toEqual([[2], [3], [4], [5]]);
132133
});
133134

134135
test('should allow to disable long press', async () => {

packages/vant/src/utils/constant.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@ export const BORDER_UNSET_TOP_BOTTOM = `${BORDER}-unset--top-bottom`;
1212
export const HAPTICS_FEEDBACK = 'van-haptics-feedback';
1313

1414
export const FORM_KEY: InjectionKey<FormProvide> = Symbol('van-form');
15+
16+
// Same as the default value of iOS long press time
17+
// https://developer.apple.com/documentation/uikit/uilongpressgesturerecognizer/1616423-minimumpressduration
18+
export const LONG_PRESS_START_TIME = 500;

0 commit comments

Comments
 (0)