본문 바로가기
개발/React

리액트 - html2pdf로 PDF 다운로드하기

by 피로물든딸기 2024. 1. 28.
반응형

리액트 전체 링크

 

참고

- Toast UI로 에디터 만들기

 

리액트에서 HTML의 요소(Toast UI Editor Viewer)를 .pdf로 다운로드 받아 보자.

링크에서 실제로 에디터를 편집하고 다운로드 받아볼 수 있다.

 

여기서는 html2pdf.js를 사용한다.

npm install html2pdf.js --legacy-peer-deps

구현

 

다운로드하고 싶은 영역을 아래와 같이 id로 추가한다. (pdf-download)

<div id="pdf-download" className="toast-editor-viewer"></div>

 

버튼을 추가해 아래 메서드를 실행하면 원하는 요소를 pdf로 다운로드 받을 수 있다.

옵션은 아래 내용을 참고하자.

  const downloadPDF = () => {
    const element = document.getElementById("pdf-download"); // PDF로 변환할 요소 선택
    html2pdf(element, {
      filename: "Toast_Editor.pdf", // default : file.pdf
      html2canvas: { scale: 2 }, // 캡처한 이미지의 크기를 조절, 값이 클수록 더 선명하다.
      jsPDF: { 
        format: "b4",  // 종이 크기 형식
        orientation: "portrait", // or landscape : 가로
      },
      callback: () => {
        console.log("PDF 다운로드 완료");
      },
    });
  };

 

전체 코드는 다음과 같다.

import React, { useEffect, useRef, useState } from "react";

import Box from "@mui/material/Box";
import Button from "@mui/material/Button";

// Toast UI Editor
import "@toast-ui/editor/dist/toastui-editor.css";
import "@toast-ui/editor/dist/toastui-editor-viewer.css"; // Viewer css
import { Editor } from "@toast-ui/react-editor";
import Viewer from "@toast-ui/editor/dist/toastui-editor-viewer";

// Dark Theme 적용
// import '@toast-ui/editor/dist/toastui-editor.css';
// import '@toast-ui/editor/dist/theme/toastui-editor-dark.css';

// Color Syntax Plugin
import "tui-color-picker/dist/tui-color-picker.css";
import "@toast-ui/editor-plugin-color-syntax/dist/toastui-editor-plugin-color-syntax.css";
import colorSyntax from "@toast-ui/editor-plugin-color-syntax";

// Table Merged Cell Plugin
import "@toast-ui/editor-plugin-table-merged-cell/dist/toastui-editor-plugin-table-merged-cell.css";
import tableMergedCell from "@toast-ui/editor-plugin-table-merged-cell";

import html2pdf from 'html2pdf.js';

const colorSyntaxOptions = {
  preset: [
    "#333333", "#666666", "#FFFFFF", "#EE2323", "#F89009", "#009A87", "#006DD7", "#8A3DB6",
    "#781B33", "#5733B1", "#953B34", "#FFC1C8", "#FFC9AF", "#9FEEC3", "#99CEFA", "#C1BEF9",
  ],
};

const CONTENT_KEY = "CONTENT_KEY";

const ToastEditor = () => {
  const editorRef = useRef(null);
  const [editMode, setEditMode] = useState(false);
  let initData = `# 제목

  ***~~<span style="color: #EE2323">내용</span>~~***
  
  * [x] 체크박스
  * [ ] 체크박스 2`;

  const handleSave = () => {
    let markDownContent = editorRef.current.getInstance().getMarkdown();
    let htmlContent = editorRef.current.getInstance().getHTML();
    console.log(markDownContent);
    console.log(htmlContent);
    localStorage.setItem(CONTENT_KEY, markDownContent);
  };

  useEffect(() => {
    let item = localStorage.getItem(CONTENT_KEY);

    if (editMode === false) {
      const viewer = new Viewer({
        el: document.querySelector(".toast-editor-viewer"),
        viewer: true,
        height: "400px",
        usageStatistics: false, // 통계 수집 거부
        plugins: [tableMergedCell],
      });

      if (item) viewer.setMarkdown(item);
      else viewer.setMarkdown(initData);
    }

    if (item) {
      if (editorRef.current) editorRef.current.getInstance().setMarkdown(item);
    } else {
      if (editorRef.current)
        editorRef.current.getInstance().setMarkdown(initData);
    }
  }, [editMode]);

  const downloadPDF = () => {
    const element = document.getElementById("pdf-download"); // PDF로 변환할 요소 선택
    html2pdf(element, {
      filename: "Toast_Editor.pdf", // default : file.pdf
      html2canvas: { scale: 2 }, // 캡처한 이미지의 크기를 조절, 값이 클수록 더 선명하다.
      jsPDF: { 
        format: "b4",  // 종이 크기 형식
        orientation: "portrait", // or landscape : 가로
      },
      callback: () => {
        console.log("PDF 다운로드 완료");
      },
    });
  };

  return (
    <div>
      <Box sx={{ m: 2 }}>
        <h1>Toast UI Editor</h1>
        <Button
          variant="outlined"
          color="secondary"
          sx={{ m: 1 }}
          onClick={() => setEditMode(!editMode)}
        >
          {editMode ? "취소하기" : "편집하기"}
        </Button>
        <Button
          variant="outlined"
          color="primary"
          sx={{ m: 1 }}
          onClick={handleSave}
          disabled={editMode === false}
        >
          저장하기
        </Button>

        <Button
          variant="outlined"
          color="warning"
          sx={{ m: 1 }}
          onClick={downloadPDF}
        >
          PDF Download
        </Button>

        {editMode === false && <div id="pdf-download" className="toast-editor-viewer"></div>}

        {editMode === true && (
          <Editor
            ref={editorRef}
            // initialValue={initContents}
            height="400px"
            placeholder="Please Enter Text."
            previewStyle="tab" // or vertical
            initialEditType="wysiwyg" // or markdown
            // hideModeSwitch={true} // 하단 숨기기
            toolbarItems={[
              // 툴바 옵션 설정
              ["heading", "bold", "italic", "strike"],
              ["hr", "quote"],
              ["ul", "ol", "task", "indent", "outdent"],
              ["table", /* "image", */ "link"],
              ["code", "codeblock"],
            ]}
            //theme="dark"
            //useCommandShortcut={false} // 키보드 입력 컨트롤 방지 ex ctrl z 등
            usageStatistics={false} // 통계 수집 거부
            plugins={[[colorSyntax, colorSyntaxOptions], tableMergedCell]}
          />
        )}
      </Box>
    </div>
  );
};

export default ToastEditor;
반응형

댓글