需求
在React中复制图片或者将截图粘贴到输入框,获取 File 文件并上传到后台并回显
实现
关键词: contenteditable, ClipboardEvent
- 首先创建一个
div元素,设置attibute属性contenteditable
<div ref={pasteRef} contenteditable="true">按 Ctrl+V 粘贴截图</div>
- 监听上述创建元素的粘贴事件
const pasteRef = useRef<HTMLDivElement>(null);
useEffect(() => {
pasteRef.current?.addEventListener("paste", onPaste);
return () => {
pasteRef.current?.removeEventListener("paste", onPaste);
};
}, [pasteRef.current, onPaste]);
- 编写监听事件。我们的需求只需要第一张图片,所以每次粘贴都对输入元素做了清空;通过判断
items中的类型获取到图片的File对象,之后就可以进行上传了。
直接使用截图软件并复制到输入框,输入框内会自动插入一个
src为base64格式的图片,在操作系统中直接对图片进行复制不会自动插入,所以这里进行了统一的处理,手动插入一张有预览地址的图片。
可以看到从windows桌面直接复制的图片并没有像截图一样展示预览图片,但是查看控制台,我们依然可以获取到
File对象。
const [copyImgFile, setCopyImgFile] = useState<File>();
const onPaste = (event: ClipboardEvent) => {
if (pasteRef.current) {
pasteRef.current.innerHTML = "";
}
const clipboardData = event.clipboardData || window.clipboardData;
const items = clipboardData.items;
let imgFile = null;
if (items?.length) {
if (items[0].type.indexOf("image") !== -1) {
imgFile = items[0].getAsFile();
}
}
const url = URL.createObjectURL(imgFile);
setTimeout(() => {
if (pasteRef.current) {
pasteRef.current.innerHTML = "";
pasteRef.current.innerHTML = `<img src="${url}" />`;
}
});
setCopyImgFile(imgFile);
};
一个小缺陷
通过上述方式实现该功能后,发现了一个小缺陷,在输入框内复制图片并展示预览图后,对输入框的图片进行 ctrl+ a选择并剪切复制,在 onPaste 方法内获取不到 File 图像文件。
对输入框内的元素进行复制粘贴,粘贴的对象类型为
type/html,并不是图片类型,但是粘贴后仍会展示预览图片,想要解决这个问题可以获取到这个预览图片的地址,再将地址转换成File文件