Skip to content

Commit bf0c57f

Browse files
984507092刘欢
authored andcommitted
fix(ImageViewer): 优化处理自定义渲染内容 (ant-design#6904)
* fix: 优化处理自定义渲染内容 * fix: 优化代码ts类型 * fix: 去掉新增属性限制完全自定义,知道用户使用HOC * fix: 移除多余逗号 * fix: 修改md和格式化 * fix: 增加FAQ备注 * fix: 优化ref逻辑处理问题 * fix: 优化ref逻辑处理问题 * fix: 增加test case * fix: 增加test case * fix: 增加test case * fix: 优化注释和代码 * fix: 修改ref逻辑,让用户自行决定是否使用 * fix: 修改ref逻辑,让用户自行决定是否使用 * fix: 调整ts类型 * fix: 格式化内容
1 parent df4884a commit bf0c57f

File tree

8 files changed

+125
-14
lines changed

8 files changed

+125
-14
lines changed

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,8 @@
4646
},
4747
"[jsonc]": {
4848
"editor.defaultFormatter": "esbenp.prettier-vscode"
49+
},
50+
"[markdown]": {
51+
"editor.defaultFormatter": "DavidAnson.vscode-markdownlint"
4952
}
5053
}

src/components/image-viewer/image-viewer.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import classNames from 'classnames'
2-
import type { FC, ReactNode } from 'react'
2+
import type { FC, ReactNode, RefObject } from 'react'
33
import React, {
44
forwardRef,
55
useCallback,
@@ -27,7 +27,10 @@ export type ImageViewerProps = {
2727
onClose?: () => void
2828
afterClose?: () => void
2929
renderFooter?: (image: string) => ReactNode
30-
imageRender?: (image: string, { index }: { index: number }) => ReactNode
30+
imageRender?: (
31+
image: string,
32+
{ ref, index }: { ref: RefObject<HTMLImageElement>; index: number }
33+
) => ReactNode
3134
classNames?: {
3235
mask?: string
3336
body?: string
@@ -88,7 +91,10 @@ export type MultiImageViewerProps = Omit<
8891
defaultIndex?: number
8992
onIndexChange?: (index: number) => void
9093
renderFooter?: (image: string, index: number) => ReactNode
91-
imageRender?: (image: string, { index }: { index: number }) => ReactNode
94+
imageRender?: (
95+
image: string,
96+
{ ref, index }: { ref: RefObject<HTMLImageElement>; index: number }
97+
) => ReactNode
9298
}
9399

94100
const multiDefaultProps = {

src/components/image-viewer/index.en.md

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ You need to click on the picture to view the details and use it with the thumbna
2121
| maxZoom | The maximum zoom ratio | `number \| 'auto'` | `3` | |
2222
| onClose | Triggered when it is closed | `() => void` | - | |
2323
| renderFooter | Render extra content on footer | `(image: string) => ReactNode` | - | |
24-
| imageRender | Custom rendering content | `(image: string, { index }: { index: number }) => ReactNode` | - | 5.39.0 |
24+
| imageRender | Custom rendering content | `(image: string,{ ref, index }: { ref: RefObject<HTMLImageElement>; index: number }) => ReactNode` | - | 5.39.0 |
2525
| visible | Whether to show or hide | `boolean` | `false` | |
2626

2727
## ImageViewer.Multi
@@ -35,7 +35,7 @@ On the basis of `ImageViewer`, the following props have been added:
3535
| images | Url list of image resources | `string[]` | - | |
3636
| onIndexChange | Triggered when the picture is switched | `(index: number) => void` | - | |
3737
| renderFooter | Render extra content on footer | `(image: string, index: number) => ReactNode` | - | |
38-
| imageRender | Custom rendering content | `(image: string, { index }: { index: number }) => ReactNode` | - | |
38+
| imageRender | Custom rendering content | `(image: string,{ ref, index }: { ref: RefObject<HTMLImageElement>; index: number }) => ReactNode` | - | |
3939

4040
At the same time, the `image` prop is removed.
4141

@@ -89,3 +89,26 @@ ImageViewer.Multi is an [uncontrolled](https://reactjs.org/docs/glossary.html#co
8989
```
9090

9191
You can use ref for manual manipulation of ImageViewer.Multi, or consider using `ImageViewer.show()`.
92+
93+
### Why doesn't my custom image preview support gestures?
94+
95+
Since the default image preview mechanism is used in ImageViewer, if custom rendering is required, the ref can be manually passed in according to actual needs, and the ref can be bound to the tag element of the custom rendering by itself.
96+
97+
```jsx
98+
<ImageViewer.Multi
99+
images={demoViewImages}
100+
visible={visible}
101+
imageRender={(image, info) => {
102+
if (info.index === 0)
103+
return (
104+
<div className={styles['image-render']} ref={info.ref}>
105+
<video muted width='100%' controls src={image} />
106+
</div>
107+
)
108+
}}
109+
defaultIndex={0}
110+
onClose={() => {
111+
setVisible(false)
112+
}}
113+
/>
114+
```

src/components/image-viewer/index.zh.md

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
| maxZoom | 最大缩放比例 | `number \| 'auto'` | `3` | |
2222
| onClose | 关闭时触发 | `() => void` | - | |
2323
| renderFooter | 渲染底部额外内容 | `(image: string) => ReactNode` | - | |
24-
| imageRender | 自定义渲染内容 | `(image: string, { index }: { index: number }) => ReactNode` | - | 5.39.0 |
24+
| imageRender | 自定义渲染内容 | `(image: string,{ ref, index }: { ref: RefObject<HTMLImageElement>; index: number }) => ReactNode` | - | 5.39.0 |
2525
| visible | 是否显示 | `boolean` | `false` | |
2626

2727
## ImageViewer.Multi
@@ -33,7 +33,7 @@
3333
| images | 图片资源的 url 列表 | `string[]` | - | |
3434
| onIndexChange | 切换图片时触发 | `(index: number) => void` | - | |
3535
| renderFooter | 渲染底部额外内容 | `(image: string, index: number) => ReactNode` | - | |
36-
| imageRender | 自定义渲染内容 | `(image: string, { index }: { index: number }) => ReactNode` | - | |
36+
| imageRender | 自定义渲染内容 | `(image: string,{ ref, index }: { ref: RefObject<HTMLImageElement>; index: number }) => ReactNode` | - | |
3737

3838
其他属性同 `ImageViewer`,但是去掉了 `image` 属性。
3939

@@ -84,3 +84,26 @@ ImageViewer.Multi 是一个[非受控](https://reactjs.org/docs/glossary.html#co
8484
```
8585

8686
你可以使用 ref 来对 ImageViewer.Multi 进行手动的操作,也可以考虑使用 `ImageViewer.show()`
87+
88+
### 为什么我自定义的图片预览不支持手势?
89+
90+
由于在 ImageViewer 中使用了默认的图片预览机制,若需进行自定义渲染,可根据实际需求手动传入 ref,并在自定义渲染的标签元素上自行绑定该 ref。
91+
92+
```jsx
93+
<ImageViewer.Multi
94+
images={demoViewImages}
95+
visible={visible}
96+
imageRender={(image, info) => {
97+
if (info.index === 0)
98+
return (
99+
<div className={styles['image-render']} ref={info.ref}>
100+
<video muted width='100%' controls src={image} />
101+
</div>
102+
)
103+
}}
104+
defaultIndex={0}
105+
onClose={() => {
106+
setVisible(false)
107+
}}
108+
/>
109+
```

src/components/image-viewer/methods.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import React from 'react'
2+
import { renderImperatively } from '../../utils/render-imperatively'
23
import {
3-
ImageViewerProps,
44
ImageViewer,
5-
MultiImageViewerProps,
5+
ImageViewerProps,
66
MultiImageViewer,
7+
MultiImageViewerProps,
78
} from './image-viewer'
8-
import { renderImperatively } from '../../utils/render-imperatively'
99

1010
export type ImageViewerShowHandler = {
1111
close: () => void

src/components/image-viewer/slide.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { animated, useSpring } from '@react-spring/web'
22
import { useSize } from 'ahooks'
3-
import type { FC, MutableRefObject, ReactNode } from 'react'
3+
import type { FC, MutableRefObject, ReactNode, RefObject } from 'react'
44
import React, { useRef } from 'react'
55
import { bound } from '../../utils/bound'
66
import type { Matrix } from '../../utils/matrix'
@@ -16,7 +16,10 @@ type Props = {
1616
onTap?: () => void
1717
onZoomChange?: (zoom: number) => void
1818
dragLockRef?: MutableRefObject<boolean>
19-
imageRender?: (image: string, { index }: { index: number }) => ReactNode
19+
imageRender?: (
20+
image: string,
21+
{ ref, index }: { ref: RefObject<HTMLImageElement>; index: number }
22+
) => ReactNode
2023
index?: number
2124
}
2225

@@ -299,7 +302,7 @@ export const Slide: FC<Props> = props => {
299302

300303
const customRendering =
301304
typeof imageRender === 'function' &&
302-
imageRender(props.image, { index } as { index: number })
305+
imageRender(props.image, { ref: imgRef, index: index ?? 0 })
303306

304307
return (
305308
<div className={`${classPrefix}-slide`}>

src/components/image-viewer/slides.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { animated, useSpring } from '@react-spring/web'
22
import { useDrag } from '@use-gesture/react'
33
import React, {
44
ReactNode,
5+
RefObject,
56
forwardRef,
67
useImperativeHandle,
78
useRef,
@@ -18,7 +19,10 @@ export type SlidesType = {
1819
maxZoom: number
1920
defaultIndex: number
2021
onIndexChange?: (index: number) => void
21-
imageRender?: (image: string, { index }: { index: number }) => ReactNode
22+
imageRender?: (
23+
image: string,
24+
{ ref, index }: { ref: RefObject<HTMLImageElement>; index: number }
25+
) => ReactNode
2226
}
2327
export type SlidesRef = {
2428
swipeTo: (index: number, immediate?: boolean) => void

src/components/image-viewer/tests/image-viewer.test.tsx

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,32 @@ describe('ImageViewer.Multi', () => {
275275
render(<App />)
276276
expect(document.querySelector('.customize-preview-node-0')).toBeTruthy()
277277
})
278+
279+
test('rendering with imageRender and ref', () => {
280+
let capturedRef: any = null
281+
function App() {
282+
return (
283+
<ImageViewer.Multi
284+
images={demoViewImages}
285+
visible
286+
imageRender={(image, info) => {
287+
capturedRef = info.ref
288+
return (
289+
<div
290+
className={`customize-preview-node-${info.index}`}
291+
ref={info.ref}
292+
/>
293+
)
294+
}}
295+
/>
296+
)
297+
}
298+
render(<App />)
299+
expect(document.querySelector('.customize-preview-node-0')).toBeTruthy()
300+
expect(capturedRef).toBeTruthy()
301+
expect(typeof capturedRef).toBe('object')
302+
expect(capturedRef.current).toBeDefined()
303+
})
278304
})
279305

280306
describe('ImageViewer', () => {
@@ -319,4 +345,27 @@ describe('ImageViewer', () => {
319345
})
320346
await waitFor(() => expect(img).not.toBeVisible())
321347
})
348+
349+
test('rendering with imageRender and ref', () => {
350+
let capturedRef: any = null
351+
function App() {
352+
return (
353+
<ImageViewer
354+
image={demoImages[0]}
355+
visible
356+
imageRender={(image, { ref, index }) => {
357+
capturedRef = ref
358+
return (
359+
<div className={`customize-preview-node-${index}`} ref={ref} />
360+
)
361+
}}
362+
/>
363+
)
364+
}
365+
render(<App />)
366+
expect(document.querySelector('.customize-preview-node-0')).toBeTruthy()
367+
expect(capturedRef).toBeTruthy()
368+
expect(typeof capturedRef).toBe('object')
369+
expect(capturedRef.current).toBeDefined()
370+
})
322371
})

0 commit comments

Comments
 (0)