复制图片或截图粘贴到输入框

912 阅读2分钟

需求

React中复制图片或者将截图粘贴到输入框,获取 File 文件并上传到后台并回显

实现

关键词contenteditable, ClipboardEvent

  1. 首先创建一个 div 元素,设置 attibute属性 contenteditable
<div ref={pasteRef} contenteditable="true">按 Ctrl+V 粘贴截图</div>
  1. 监听上述创建元素的粘贴事件
const pasteRef = useRef<HTMLDivElement>(null);

useEffect(() => {
    pasteRef.current?.addEventListener("paste", onPaste);
    return () => {
          pasteRef.current?.removeEventListener("paste", onPaste);
    };
}, [pasteRef.current, onPaste]);
  1. 编写监听事件。我们的需求只需要第一张图片,所以每次粘贴都对输入元素做了清空;通过判断 items 中的类型获取到图片的File 对象,之后就可以进行上传了。

直接使用截图软件并复制到输入框,输入框内会自动插入一个 srcbase64 格式的图片,在操作系统中直接对图片进行复制不会自动插入,所以这里进行了统一的处理,手动插入一张有预览地址的图片。

image.png

image.png

可以看到从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 文件

image.png

参考文档

## 直接剪切板粘贴上传图片的前端JS实现-张鑫旭

DataTransferItem-MDN