본문 바로가기
Vue.js

PDF 다운로드 기능 구현(html2pdf.js)

by whoyoung90 2022. 12. 15.
반응형

 

회사 웹사이트에서 특정영역을 pdf 파일로 다운로드가 필요하여 라이브러리를 찾아보게 되었고
html2pdf.jsvue-html2pdf가 있었다.

 

> vue-html2pdf

"vue html to pdf" 라고 구글에 검색하면 가장 먼저 나오고 사용량이 가장 많은 vue-html2pdf은

html2pdf.js를 vue 컴포넌트 형식으로 제공한다.

 

기존 html2pdf.js와 다르게 미리보기 창을 띄워주는 preview-modal 옵션처럼 장점이 있는 반면,

slot으로 pdf에 들어갈 내용을 넣어야 하는데 slot안에 내용이 있는 태그들을 넣게 되면 해당 태그들은 웹에서 보여지지 않기 때문에

같은 내용을 한번 더 써줘야 하는 번거로움이 생긴다.

 

단시간에 단순구조로 pdf를 다운로드 할 수 있도록 하는 것이 목표였기 때문에

원래 vue-html2pdf도 html2canvas와 jsPDF 기반으로 만들어져있어 본래의 html2pdf을 사용하기로 결정했다.

 

※ 참고답변

stackoverflow.com/questions/60204249/impossible-to-convert-html-code-to-pdf-with-vue-html2pdf

 

> html2pdf.js

vue 컴포넌트 형식의 라이브러리는 아니지만 plugin으로 만들어서 사용하니 간단했다.

 

설치

공식 github에서 최신 버전이 아닌 0.9.3버전을 추천하여 해당 버전을 설치한다.

https://github.com/eKoopmans/html2pdf.js/tree/bugfix/clone-nodes-BUILD

$yarn add html2pdf.js@^0.9.3

 

html2pdf.js를 vue plugin으로 설정

html2pdf.js를 vue plugin으로 등록해 놓으면 프로젝트 내에서 import할 필요 없어 코드를 줄일 수 있어 설정했다.

 

파일 이름 및 경로: src/plugins/htmlToPdf.js

/* htmlToPdf.js */
import html2pdf from "html2pdf.js";

const methods = {
  htmlToPdf: (location, fileName) => {
    html2pdf()
      .set({
        margin: 0, // 다운로드된 pdf 파일의 마진 여백
        filename:
          navigator.userAgent.indexOf("MSIE") !== -1 ||
            navigator.appVersion.indexOf("Trident/") > -1
            ? `${fileName}.pdf`
            : fileName,
        // filename에서 IE11은 .pdf를 자동으로 넣어주지 않아 .pdf를 파일명에 넣어줘야 한다.

        pagebreak: { mode: "avoid-all" },
        image: { type: "jpeg", quality: 1 }, // pdf 들어갈 영역을 사진을 찍어 변환 하는 이미지 퀄리티
        html2canvas: {
          width: 793.7, // a4 width
          height: 1122.5, // a4 height

          useCORS: true, // 영역 안에 로컬 이미지를 삽입 할 때 옵션 필요
          scrollY: 0, // 스크롤 이슈 ⭐️
          scale: 3, // browsers device pixel ratio
          dpi: 300,
          letterRendering: true,
          allowTaint: false, // useCORS를 true로 설정시 반드시 allowTaint를 false 해주어야함
        },
        jsPDF: { orientation: "portrait", unit: "mm", format: "a4" },
      })
      .from(location)
      .save();
  },
};

export default {
  install(Vue) {
    Vue.prototype.$htmlToPdf = methods.htmlToPdf;
  },
};
⭐️ 스크롤이 맨 아래에 가있는 상태에서 download버튼을 누르면,
pdf의 이미지캡처가 해당스크롤을 기준으로 출력하므로 앞부분의 page가 빈 상태로 나오는 문제가 생긴다.
그러므로 scrollY: 0 옵션을 추가하여 세로 scroll위치 0부터 pdf를 전부 출력하도록 하자. 

 

 

main.js에 가서 plugins/htmlToPdf.js를 import 후 등록해준다.

/* main.js */
import htmlToPdf from "./plugins/htmlToPdf";
Vue.use(htmlToPdf);

 

vue 예시 파일

<template>
  <div>
    // ...
    <!-- pdf에 들어갈 내용 -->
    <article class="pdf-wrapper" ref="pdfArea" :key="pdfKey">
      // ...
    </article>
    <!-- pdf 다운로드 버튼 -->
    <section class="pdf-button" @click="htmlToPDF">PDF 내려받기</section>
  </div>
</template>

<script>
export default {
  data: () => ({
    pdfKey: 0,
  }),

  methods: {
    htmlToPDF() {
      const name = 'document';
      this.$htmlToPdf(this.$refs.pdfArea, name);
      this.pdfKey += 1;
    },
  },
};
</script>

pdf로 변환 후 radio box에 있던 값이 사라지는 버그가 생긴다면
그걸 방지하기 위해 pdf 변환 후 강제로 컴포넌트를 다시 load해줘야 한다.


간편하게 하기 위해 pdf의 영역 컴포넌트에 key로 변수를 넣고 해당 변수를 pdf변환 끝날 때 +1를 해주어 key를 변경시킨다.
key가 변경되면 해당 컴포넌트를 다시 load 시켜준다.

 

[참고 URL]

https://velog.io/@adc0612/vue-html2pdf.js-%EC%A0%81%EC%9A%A9

 

A4 용지 크기

가로: 21cm 👉 793.7px

세로: 29.7cm 👉 1122.5px

/* pdf에 들어갈 내용 */
.pdf-wrapper {
  width: 793.7px; 
  height: 1122.5px;
}

 


🚫 CSS rules are not getting applied

PDF 파일을 다운로드 받았을때 외부 스타일시트(scss파일 등)가 적용되지 않는 이슈가 발생할 수 있다.

PDF 내용과 관련없는 상단 태그들과 unnesting해야 css가 적용된다 !!
 

1. 인라인 스타일로 직접 작성

https://github.com/eKoopmans/html2pdf.js/issues/219#issuecomment-499819399

2. sass사용시 unnesting

https://github.com/eKoopmans/html2pdf.js/issues/219#issuecomment-768583651

 

 

반응형

'Vue.js' 카테고리의 다른 글

딥셀렉터(v-deep) 설정하는 방법  (0) 2022.12.13
v-if와 v-show의 차이점과 사용 방법  (0) 2022.11.23
구글 애널리틱스 적용하기 1편(vue-gtag)  (0) 2022.10.20
Vue 초기 세팅  (0) 2021.08.08

댓글