前言
做的需求需要可以在页面上拖拽和粘贴图片,为了在多个地方复用就封装成 hook 来使用。实现思路都是通过外部调用时主动传入 ref 在上面绑定监听事件。废话不多说,直接上代码吧。
拖拽文件
import React, { useCallback, useEffect, useState } from 'react';
export interface ImageDropInProps {
ref: React.RefObject<HTMLDivElement>;
onFinished?: (files: File[]) => Promise<void> | void;
}
export default function useDragInImage(props: ImageDropInProps) {
const { ref, onFinished } = props;
const [isDrop, setIsDragOver] = useState(false);
const onDrop = useCallback(
async (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
setIsDragOver(false);
const { files } = event.dataTransfer;
if (!files) {
return;
}
const selectedFiles = Array.from(files);
onFinished?.(selectedFiles);
},
[onFinished]
);
const onDragOver = useCallback((event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
setIsDragOver(true);
}, []);
const onDragLeave = useCallback((event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
setIsDragOver(false);
}, []);
useEffect(() => {
if (!ref.current) {
return;
}
const dragInImage = ref.current;
const onDropListener = (event: DragEvent) => {
onDrop(event as unknown as React.DragEvent<HTMLDivElement>);
};
const onDragOverListener = (event: DragEvent) => {
onDragOver(event as unknown as React.DragEvent<HTMLDivElement>);
};
const onDragLeaveListener = (event: DragEvent) => {
onDragLeave(event as unknown as React.DragEvent<HTMLDivElement>);
};
dragInImage.addEventListener('drop', onDropListener);
dragInImage.addEventListener('dragover', onDragOverListener);
dragInImage.addEventListener('dragleave', onDragLeaveListener);
return () => {
dragInImage.removeEventListener('drop', onDropListener);
dragInImage.removeEventListener('dragover', onDragOverListener);
dragInImage.removeEventListener('dragleave', onDragLeaveListener);
};
}, [onDragLeave, onDragOver, onDrop, ref]);
return { isDrop };
}
复制文件
import React, { useCallback, useEffect } from 'react';
export interface ParseImageProps {
ref: React.RefObject<HTMLDivElement>;
onFinished?: (files: File[]) => Promise<void> | void;
}
export default function useParseImage(props: ParseImageProps) {
const { ref, onFinished } = props;
const onParse = useCallback(
async (event: React.ClipboardEvent<HTMLDivElement>) => {
const { clipboardData } = event;
if (!clipboardData) {
return;
}
const { items } = clipboardData;
if (!items) {
return;
}
const files = Array.from(items).map(item => item.getAsFile()) as File[];
if (!files) {
return;
}
onFinished?.(files);
},
[onFinished]
);
useEffect(() => {
if (!ref.current) {
return;
}
const { current } = ref;
const onParseListener = (event: ClipboardEvent) => {
onParse(event as unknown as React.ClipboardEvent<HTMLDivElement>);
};
current.addEventListener('paste', onParseListener);
return () => {
current.removeEventListener('paste', onParseListener);
};
}, [onParse, ref]);
}