본문 바로가기

HTML + JAVASCRIPT + CSS/ReactJS+AngularJS +VueJS

클립보드의 이미지를 업로드 후 화면 표기 처리

onPaste contentEditable 을 이용한 이미지 붙여 넣기 처리

페이스북 댓글창에서 클립보드에 저장(Ctrl+C) 된 이미지를 붙여넣기(Ctrl+V)를 하면, 이미지가 업로드 되는 것을 확인 할 수 있습니다.

이를 구현 하기 위해서는 우선 다음 HTMLElement.onpaste 이벤트에 대하여 알아야합니다.

간단하게 요약하면 붙여넣기를 처리할때 호출되는 이벤트 인데요. 붙여넣는 이벤트에서 이미지일 경우 업로드 처리를 하면 됩니다.

구현하기

구현은 React.js기반으로 구현 하였습니다.

import React from "react";
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import "./styles.css";

// 서버 없이 테스트를 위해서 axios-mock-adapter 사용
const mock = new MockAdapter(axios);
mock.onPost("/fileupload").reply(200, {
  seq: 1
});

// 원래 소스는 `<img src="/download/${seq}" width="100%"/>`;
const buildImageHtml = (seq) =>
  `<img src="https://lahuman.github.io/assets/img/logo.png" width="100%"/>`;

export default function App() {
  const comment = React.useRef();

  const fileUpload = async (blob) => {
    const formData = new FormData();
    formData.append("file", blob);
    const { data: fileInfo } = await axios.post(`/fileupload`, formData);
    return fileInfo;
  };

  const focusMoveWithFile = () => {
    comment.current.focus();
    if (
      typeof window.getSelection !== "undefined" &&
      typeof document.createRange !== "undefined"
    ) {
      const range = document.createRange();
      range.selectNodeContents(comment.current);
      range.collapse(false);
      const sel = window.getSelection();
      if (!sel) return;
      sel.removeAllRanges();
      sel.addRange(range);
    }
  };

  return (
    <div
      ref={comment}
      contentEditable="true"
      className="comment"
      suppressContentEditableWarning
      onPaste={async (event) => {
        // event.preventDefault(); 이 없을 경우 upload와 상관 없이 이미지가 붙음
        event.preventDefault();
        const item = event.clipboardData.items[0];
        if (item.type.indexOf("image") === 0) {
          const blob = item.getAsFile();
          const { seq } = await fileUpload(blob);
          const text = `${comment.current.innerHTML}${buildImageHtml(seq)}`;
          comment.current.innerHTML = text;
          focusMoveWithFile();
        } else {
          // 이미지가 아닐 경우 text로 처리 
          const paste = event.clipboardData.getData("text");
          if (paste) {
            const selection = window.getSelection();
            if (!selection) return;
            if (selection && !selection.rangeCount) return;
            selection?.deleteFromDocument();
            selection?.getRangeAt(0).insertNode(document.createTextNode(paste));
          }
        }
      }}
      placeholder="글을 작성해주세요 (글 작성 꿀팁 : 여기에 이미지를 Ctrl+C, Ctrl+V로 바로 붙여넣기 할 수 있어요!)"
    />
  );
}

예제 바로가기

기능은 생각보다 어렵지 않았고 재미있었다.

참고자료