[vue 프로젝트] html2pdf.js 적용

adc0612·2022년 4월 2일
4

vue 프로젝트 기록

목록 보기
4/5
post-custom-banner

들어가며

프로젝트에서 특정영역을 pdf로 저장이 필요해 라이브러리를 찾아봤다.
html2pdf.js와 vue-html2pdf가 있었다.

vue-html2pdf

vue용 html2pdf.js

vue-html2pdf github 페이지

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

<template>
   <div>
     <vue-html2pdf
        :show-layout="false"
        :float-layout="true"
        :enable-download="true"
        :preview-modal="true"
        :paginate-elements-by-height="1400"
        filename="hee hee"
        :pdf-quality="2"
        :manual-pagination="false"
        pdf-format="a4"
        pdf-orientation="landscape"
        pdf-content-width="800px"

        @progress="onProgress($event)"
        @hasStartedGeneration="hasStartedGeneration()"
        @hasGenerated="hasGenerated($event)"
        ref="html2Pdf"
    >
        <section slot="pdf-content">
            <!-- PDF Content Here -->
        </section>
    </vue-html2pdf>
   </div>
</template>

기존 html2pdf.js와 다르게 미리보기 창을 띄워주는 preview-modal 옵션이 있어서 좋았다.

하지만 slot으로 pdf안으로 들어갈 내용을 넣어야 하는데 slot안에 내용이 있는 태그들을 넣게 되면 해당 태그들은 웹에서 보여지지 않기 때문에 같은 내용을 한번 더 써줘야 하는 번거로움이 생긴다.
component태그를 이용해 버튼을 누르면 vue-html2pdf로 바꿔줬었지만 ie11에서 에러가 있어 사용하지 않았다.

html2pdf.js

html2pdf.js

html2pdf.js github 페이지

vue의 컴포넌트 형식의 라이브러리는 아니지만 plugin으로 만들어서 사용하니 간단했다.
ie11에서도 잘 작동돼서 선택했다.

설치

npm을 이용해 라이브러리를 설치했다.

npm install --save html2pdf.js@0.9.3

버전은 0.9.3을 추천한다. 공식 github에서도 0.9.3버전을 추천한다.
그냥 html2pdf가 아니고 html2pdf.js이다.

옵션 (Options)

html2pdf.js에서 제공되는 옵션은 html2pdf.js options (github)에 들어가면 잘 나와있다.
html2pdf.js는 html2canvas와 jspdf의 기능을 넣은 라이브러리이기 때문에 두 라이브러리의 옵션도 넣을 수 있다.
html2canvas 옵션 목록 페이지
jspdf 옵션 목록 페이지

사용한 옵션

const options = {
        margin: [15, 0, 15, 0], // top, right, bottom, left 마진 여백
        filename: 'document', // Pdf 파일 명
        pagebreak: { mode: 'avoid-all' }, // pagebreak 옵션
        image: { type: 'jpeg', quality: 1 }, // 이미지 퀄리티 (pdf 들어갈 영역을 사진을 찍어 변환 하기 때문에 이미지 퀄리티 = pdf 퀄리티
        html2canvas: { // html2canvas 옵션
          useCORS: true, // 영역 안에 로컬 이미지를 삽입 할 때 옵션 필요
          scrollY: 0, // 스크롤 이슈 때문에 필수 
          scale: 1, // browsers device pixel ratio
          dpi: 300,
          letterRendering: true,
          allowTaint: false, //useCORS를 true로 설정 시 반드시 allowTaint를 false처리 해주어야함
        },
        jsPDF: { orientation: 'portrait', unit: 'mm', format: 'a4' },
      };

스크롤이 맨 아래에 가있는 상태에서 download버튼을 누르면, pdf의 이미지캡처가 해당스크롤을 기준으로 출력하므로 앞에 몇장의 page가 빈 상태로 나오는 문제가 생긴다.
그러므로 scrollY: 0 옵션을 넣으면 pdf는 알아서 세로 scroll위치 0부터 pdf를 잘 출력할 수 있다.

html2pdf.js vue plugin으로 설정

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

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

htmlToPdf.js

import html2pdf from 'html2pdf.js'; //html2pdf 라이브러리 import
const methods = {
  // location은 pdf영역 tag
  // fileName은 PDF 파일 명
  htmlToPdf: (location, fileName) => {
    html2pdf()
      .set({
        margin: [15, 0, 15, 0],
      	// filename에서 IE11은 .pdf를 자동으로 넣어주지 않아 .pdf를 파일 명에 넣어줘야 한다.
        filename: navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > -1 ? `${fileName}.pdf` : fileName,
        pagebreak: { mode: 'avoid-all' },
        image: { type: 'jpeg', quality: 1 },
        html2canvas: {
          useCORS: true,
          scrollY: 0,
          scale: 1,
          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;
  },
};

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

import htmlToPdf from 'plugins/htmlToPdf';
Vue.use(htmlToPdf);

예제 - vue 파일

<template>
	<div>
 		<a href="javascript:void(0);" @click="htmlToPDF">
        <!-- key를 넣어주면 컴포넌트를 다시 load해준다. -->
        <div ref="pdfArea" :key="pdfKey">
        	<!-- pdf에 들어갈 내용 내용 -->
        </div>
 	</div>
</template>

<script>
export default {
  data() {
    return {
      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 시켜준다.

post-custom-banner

2개의 댓글

comment-user-thumbnail
2022년 6월 29일

//useCORS를 true로 설정 시 반드시 allowTaint를 false처리 해주어야함 이부분은 왜 그런건가요?
다른 예제 보면 둘다 true로 되어있는 경우가 있던데

답글 달기
comment-user-thumbnail
2022년 11월 30일

감사합니다:) 덕분에 radio 버그 해결되었어요~

답글 달기