개요
Vue 프로젝트에서 HTML 내용을 Word 문서로 내보내는 방법에 대해 설명합니다. 이 방법은 템플릿이 필요 없으며, echarts 차트도 포함하여 내보낼 수 있습니다. html-docx-js와 file-saver 패키지를 사용하여 구현합니다.
구현 방식은 다음과 같습니다:
- HTML 요소 가져오기
- 페이지의 Canvas 요소를 이미지로 변환
- 변환된 이미지를 Word 파일에 포함하여 내보내기
설치
npm install html-docx-js --save
npm install file-saver --save
내보내기 모듈 구현
exportWord.js 파일을 생성하여 Word 내보내기 기능을 구현합니다.
// exportWord.js
import htmlDocx from 'html-docx-js/dist/html-docx';
import saveAs from 'file-saver';
/**
* HTML을 Word 문서로 내보내기
* @param fileName 내보낼 파일 이름
* @param elementSelector 선택자 문자열
*/
export function exportWord(fileName, elementSelector) {
const targetElement = document.querySelector(elementSelector);
const clonedElement = targetElement.cloneNode(true);
const originalCanvases = targetElement.getElementsByTagName('canvas');
const clonedCanvases = clonedElement.getElementsByTagName('canvas');
const conversionPromises = Array.from(originalCanvases).map((canvas, index) => {
return new Promise((resolve) => {
const dataUrl = canvas.toDataURL('image/png', 1.0);
const imageElement = new Image();
imageElement.onload = () => {
URL.revokeObjectURL(dataUrl);
resolve();
};
imageElement.src = dataUrl;
// 클론된 DOM의 canvasの前に画像を挿入
clonedCanvases[index].parentNode.insertBefore(
imageElement,
clonedCanvases[index]
);
});
});
// 元のcanvasを削除
const clonedCanvasElements = clonedElement.getElementsByTagName('canvas');
Array.from(clonedCanvasElements).forEach((canvas) => {
canvas.parentNode.removeChild(canvas);
});
Promise.all(conversionPromises).then(() => {
convertImagesToBase64(clonedElement);
const wordBlob = htmlDocx.asBlob(`
<html xmlns:o='urn:schemas-microsoft-com:office:office'
xmlns:w='urn:schemas-microsoft-com:office:word'
xmlns='http://www.w3.org/TR/REC-html40'>
<head>
<style>
${document.head.outerHTML}
</style>
</head>
<body>
${clonedElement.outerHTML}
</body>
</html>
`);
saveAs(wordBlob, fileName);
});
}
/**
* 画像データをBase64形式に変換
* @param clonedElement クローンされた要素
*/
function convertImagesToBase64(clonedElement) {
const imageElements = clonedElement.getElementsByTagName('img');
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
for (let i = 0; i < imageElements.length; i++) {
const img = imageElements[i];
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(
img,
0,
0,
img.width * 0.8,
img.height * 0.8
);
const extension = img.src
.substring(img.src.lastIndexOf('.') + 1)
.toLowerCase();
const base64Data = canvas.toDataURL('image/' + extension);
img.setAttribute('src', base64Data);
}
canvas.remove();
}
Vue 컴포넌트에서 사용
내보내기 기능을 사용할 Vue 컴포넌트의 예제입니다.
<template>
<div>
<div>
<el-row>
<button type="button" @click="handleExportWord">Word 내보내기</button>
</el-row>
<div id="contentDom" style="text-align: center" class="export-area">
<div>내용 영역</div>
</div>
</div>
</div>
</template>
<script>
import { exportWord } from '@/utils/feature/exportWord';
export default {
name: "WordExport",
data() {
return {
// 데이터 속성
}
},
methods: {
// HTML을 Word로 변환
handleExportWord() {
exportWord('report.docx', '.export-area');
}
}
}
</script>
<style scoped>
</style>
작동 원리
이 구현의 핵심적인 작동 방식은 다음과 같습니다:
- DOM 복제: 선택한 HTML 요소를 복제합니다.
- Canvas 변환: echarts 같은 차트 라이브러리는 Canvas를 사용하므로, Canvas 요소를 Base64 형식의 이미지로 변환합니다.
- 이미지 변환: 기존의 이미지들도 Base64로 변환하여 Word 문서에 포함시킵니다.
- Word 생성: HTML_DOCX 라이브러리를 사용하여 변환된 HTML을 Word Blob으로 변환하고 file-saver로 다운로드합니다.
참고 사항
- CSS 스타일이 Word 문서에 그대로 반영됩니다.
- 복잡한 차트나 그래프가 포함된 경우에도 Canvas를 이미지로 변환하여 깔끔하게 내보낼 수 있습니다.
- Word 문서의 크기나 레이아웃은 CSS로 조정할 수 있습니다.