69 行
2.3 KiB
JavaScript
69 行
2.3 KiB
JavaScript
import './ImagePreview.css';
|
|
|
|
import { useCallback, useRef, useState, useEffect, Fragment } from 'react';
|
|
import Spinner from '../Spinner/Spinner';
|
|
|
|
export default function ImagePreview({ image }) {
|
|
const [isScaled, setIsScaled] = useState(false);
|
|
const [transform, setTransform] = useState('');
|
|
const imgRef = useRef(null);
|
|
const [loading, setLoading] = useState(false);
|
|
const imgWidth = useRef(0), imgHeight = useRef(0);
|
|
|
|
useEffect(() => {
|
|
setLoading(true);
|
|
let img = new Image();
|
|
img.onload = () => {
|
|
setLoading(false);
|
|
imgWidth.current = img.width;
|
|
imgHeight.current = img.height;
|
|
};
|
|
img.src = image;
|
|
}, [image]);
|
|
|
|
const scale = useCallback(() => {
|
|
if (isScaled) return;
|
|
let el = imgRef.current;
|
|
let { x, y } = el.getBoundingClientRect();
|
|
let { innerWidth, innerHeight } = window;
|
|
let initialScale = 200 / imgHeight.current,
|
|
terminalScale = Math.min(1, Math.min((innerWidth - 10) / imgWidth.current, (innerHeight - 10) / imgHeight.current));
|
|
setTransform(`translate(${x + (imgWidth.current * initialScale - innerWidth) / 2}px, ${y + (200 - innerHeight) / 2}px) scale(${initialScale})`);
|
|
setIsScaled(true);
|
|
setTimeout(() => {
|
|
setTransform(`translate(0, 0) scale(${terminalScale})`);
|
|
}, 0);
|
|
}, [isScaled]);
|
|
|
|
const unscale = useCallback(() => {
|
|
if (!isScaled) return;
|
|
let el = imgRef.current;
|
|
let { x, y } = el.getBoundingClientRect();
|
|
let { innerWidth, innerHeight } = window;
|
|
let initialScale = 200 / imgHeight.current;
|
|
setTransform(`translate(${x + (imgWidth.current * initialScale - innerWidth) / 2}px, ${y + (200 - innerHeight) / 2}px) scale(${initialScale})`);
|
|
setIsScaled(true);
|
|
setTimeout(() => {
|
|
setIsScaled(false);
|
|
}, 300);
|
|
}, [isScaled]);
|
|
|
|
return (
|
|
<div className="preview">
|
|
{
|
|
loading ? (
|
|
<div className="spinner-wrap">
|
|
<Spinner isGray />
|
|
</div>
|
|
) : (
|
|
<Fragment>
|
|
<img src={image} alt="图片" onClick={scale} ref={imgRef} />
|
|
<div className={isScaled ? 'scaled-wrap open' : 'scaled-wrap'} onClick={unscale}>
|
|
<img className="scaled-image" src={image} alt="图片" style={{ transform }} />
|
|
</div>
|
|
</Fragment>
|
|
)
|
|
}
|
|
</div>
|
|
);
|
|
} |