原文链接: 手写一个 React 图片预览组件
前几天打算给博客添加一个图片预览的效果,可在网上找了半天也没找到合适的库,于是自己干脆自己手写了个。
最终实现效果如下:
实现原理
当鼠标点击图片时生成一个半透明遮罩,并添加一个与点击图片位置大小都相同的图片,之后通过 CSS 实现图片的放大和居中,当再次点击时,通过删除样式实现图片的返回。
具体操作
添加遮罩和图片
此处需要用到 ReactDom 的 createPortal()
方法,它可以将元素渲染到网页中的指定位置。因为要考虑到图片的返回,所以图片的位置不能用 getBoundingClientRect()
提供的相对于视图窗口的坐标,而是要用到 offsetTop
和 offsetLeft
提供的相对于 offsetParent 的坐标,所以需要将遮罩和图片渲染到 body 元素中,并且二者需要为同一级。具体实现代码如下:
import {
createPortal } from 'react-dom';
import {
useState, useRef } from 'react';
function Mask({
props, setStatus, imgRef }) {
const close = () => {
setStatus(false);
};
return createPortal(
<div onClick={
close} className='cursor-zoom-out'>
<div className='fixed bottom-0 left-0 right-0 top-0 bg-black/75'></div>
<img
{
...props}
className='absolute'
style={
{
top: imgRef.current.offsetTop,
left: imgRef.current.offsetLeft,
width: imgRef.current.offsetWidth,
height: imgRef.current.offsetHeight,
}}
/>
</div>,
document.body
);
}
export default function Img(props) {
const [status, setStatus] = useState(false);
const imgRef = useRef(null);
return (
<>
<img
{
...props}
ref={
imgRef}
className={
`cursor-zoom-in ${
status ? 'invisible' : ''}`}
onClick={
() => {
setStatus(true);
}}