Install
Run the following commands in the React
project directory:
pnpm:
pnpm i react-photo-view
yarn:
yarn add react-photo-view
or with npm:
npm install react-photo-view
Quick start
Import the CSS
file at the entry point of the application
import 'react-photo-view/dist/react-photo-view.css';
Introduce PhotoProvider
and PhotoView
components where they need to be used, basic usage:
import { PhotoProvider, PhotoView } from 'react-photo-view';
export default function MyComponent() {
return (
<PhotoProvider>
<div className="foo">
{images.map((item, index) => (
<PhotoView key={index} src={item}>
<img src={item} alt="" />
</PhotoView>
))}
</div>
</PhotoProvider>
);
}
With the PhotoProvider
as the boundary, all the PhotoView
images in it will be extracted as a set of image preview galleries in the running order. When an <img >
is clicked, it will locate the specified image and open the preview:
If you need the images of the entire page to form a group for preview, you can nest PhotoProvider
at the entrance of the page.
Note: react-photo-view
only keeps three images loaded in the DOM
at a time, since each image is a compositing
layer, which consumes quite a bit of memory.
Animation
Transition effect
react-photo-view
uses quite a lot of CSS3
animations to ensure a smoother experience, and uses spring animations to stay close to the native scrolling effect when scrolling. CSS3
animations have a default duration of 400ms
, using the cubic-bezier(0.25, 0.8, 0.25, 1)
animation function.
You can customize the animation time or function by setting speed
, easing
:
<PhotoProvider
speed={() => 800}
easing={(type) => (type === 2 ? 'cubic-bezier(0.36, 0, 0.66, -0.56)' : 'cubic-bezier(0.34, 1.56, 0.64, 1)')}
/>
speed
and easing
are functions. The type of the current animation can be judged by the parameter type
. The values of type
are:
1
- open2
- closing3
- toggleindex
img
node, an additional opacity
fade effect will be added.Crop Thumbnails
The <PhotoView>
component automatically recognizes the child node type, and if the child node is <img >
, and the object-fit
property is set using CSS
, it will have a cropping effect in the zoom animation:
<PhotoView src={imageURL}>
<img src={imageURL} style={{ objectFit: 'cover' }} alt="" />
</PhotoView>
Custom toolbar
Add parameter toolbarRender
function to <PhotoProvider>
, which must return a ReactNode
node.
Zoom in or zoom out
Add a scale
control to achieve zoom in and out buttons:
<PhotoProvider
toolbarRender={({ onScale, scale }) => {
return (
<>
<svg className="PhotoView-Slider__toolbarIcon" onClick={() => onScale(scale + 1)} />
<svg className="PhotoView-Slider__toolbarIcon" onClick={() => onScale(scale - 1)} />
</>
);
}}
/>
Rotate
react-photo-view
does not have a built-in rotation control button by default, but provides a rotation API
. We can achieve the rotation effect by simply adding an SVG
image:
<PhotoProvider
toolbarRender={({ rotate, onRotate }) => {
return <svg className="PhotoView-Slider__toolbarIcon" onClick={() => onRotate(rotate + 90)} />;
}}
/>
The parameters provided by the toolbarRender
function are:
images
- list of imagesDataType[]
index
- the current indexnumber
onIndexChange
- index change callback(index: number) => void
visible
- whether to seeboolean
onClose
- close event callback() => void
overlayVisible
- whether the overlay is visibleboolean
overlay
- Overlayrotate
- the current rotation anglenumber
onRotate
- Rotate event callback(rotate: number) => void
scale
- the current scalenumber
onScale
- Scale event callback(scale: number) => void
The following example implements a rotating full-screen zoom in and out toolbar:
Long image mode
When loading images whose aspect ratio exceeds 3
times, the mobile device will enter the long image mode by default. That is, the preview starts at the top of the image, and the width of the image fills the width with the mobile device:
Trigger node
<PhotoView>
child components can be of the regular React.HTMLAttributes
type, such as <img>
, <div>
, etc.
If it is a custom component, you need to ensure that onClick
event can be triggered normally, and forward ref
to HTMLElement
to ensure the correctness of opening and closing the animation source.
<PhotoView src={imageURL}>
<Button primary>Click</Button>
</PhotoView>
PhotoSlider
In general, using <PhotoProvider>
in combination with <PhotoView>
already suffices for most needs. For more advanced custom controls, <PhotoSlider>
can be used.
The parameters of <PhotoSlider>
are inherited from <PhotoProvider>
. Several additional APIs are exposed:
images
list of images,DataType[]
visible
whether the controlled propertyboolean
is visibleonClose
close event callback() => void
afterClose
callback after closing animation() => void
index
The current index controlled propertynumber
onIndexChange
index change callback(index: number) => void
visible
is controlled with onClose
, and index
is controlled with onIndexChange
.
export default function MyComponent() {
const [visible, setVisible] = useState(false);
const [index, setIndex] = useState(0);
return (
<>
<Button onClick={() => setIndex(2)}>setIndex(2)</Button>
<Button onClick={() => setIndex(4)}>setIndex(4)</Button>
<Button onClick={() => setVisible(true)} primary>
Click
</Button>
<PhotoSlider
images={images.map((item) => ({ src: item, key: item }))}
visible={visible}
onClose={() => setVisible(false)}
index={index}
onIndexChange={setIndex}
/>
</>
);
}
Preview more
<PhotoView >
can also be added to the preview queue without subcomponents, but it cannot directly trigger the preview of the current picture. Through this feature, we can realize the function of previewing more pictures through an entrance:
<PhotoProvider>
{images.map((item, index) => (
<PhotoView key={index} src={item}>
{index < 2 ? <img src={item} alt="" /> : undefined}
</PhotoView>
))}
</PhotoProvider>
Custom render node
<PhotoView>
has built-in support for image preview by default, just pass src
, the component will automatically recognize the width and height of the image.
We can also implement the preview of custom nodes through the render
function to support the needs of video
or pdf
.
const elementSize = 400;
function MyComponent() {
return (
<PhotoView
width={elementSize}
height={elementSize}
render={({ scale, attrs }) => {
const width = attrs.style.width;
const offset = (width - elementSize) / elementSize;
const childScale = scale === 1 ? scale + offset : 1 + offset;
return (
<div {...attrs}>
<div style={{ transform: `scale(${childScale})`, width: elementSize, transformOrigin: '0 0' }}>
<div>Hello world</div>
<Button>button</Button>
<input onMouseDown={(e) => e.stopPropagation()} />
</div>
</div>
);
}}
>
<Button primary>Click</Button>
</PhotoView>
);
}
Note: After the gallery is zoomed, it will first be scaled with scale
, and after the animation is over, it will be
adjusted to the width and height corresponding to the current scale
, and the scale
will be reset to 1
.
PhotoProvider parameter
Custom description
Add the overlayRender
function to <PhotoProvider>
to implement custom nodes. The return value of the function parameter is the same as that of toolbarRender
.
Loop preview
Add parameter loop
on <PhotoProvider>
to change the number of loop previews. Set to boolean
to enable and disable, set to number
type to exceed the specific number to enable loop preview, the default value is 3
sheets:
<PhotoProvider loop={4} />
Mask Transparency
The default is opaque, and the transparency will gradually decrease during the pull-up process. You can add maskOpacity
to <PhotoProvider>
to adjust the default transparency, which can be set to a number between 0-1
:
<PhotoProvider maskOpacity={0.5} />
Don't show top button area
Set bannerVisible
to false
to hide the top area:
<PhotoProvider bannerVisible={false} />
Masking event
pullClosable
(default true
) can close the gallery by pulling down, maskClosable
(default true
) can click on the mask to close the gallery:
<PhotoProvider pullClosable={false} maskClosable={false} />
Custom feedback
<PhotoView>
If loading fails, empty nodes are rendered by default, and you may need to set your own error feedback nodes according to the current UI.
brokenElement
- set the load failure patternReact.ReactElement
loadingElement
- set the loading patternReact.ReactElement