【Vue 實踐】頁面生成 pdf 檔案-01

shanyuhai123發表於2019-03-26

介紹

為了找工作,花了七八天完成了自己的線上簡歷,結果發現並沒有人來看這東西。

說實話,這個是自己的第一個前後端專案,自我感覺還好,結果根本沒人在意,一定是我做得太差,那就得好好改這個專案,增加功能。

新增的下載簡歷效果圖:

【Vue 實踐】頁面生成 pdf 檔案-01

廣告:
Github 地址
三個月工作經驗找前端工作

規範化

在開始動工之前,需要考慮自己做什麼了,沒有接觸大公司的規範的開發流程,那也得自己編一個出來。

如果有了解如何進行規範化開發的,希望能夠在下方評論處給予我一些參考連結 :smile_cat:

建立 Issue

【Vue 實踐】頁面生成 pdf 檔案-01

想一下目前要做的事情,提上對應的 Issue,再加上對應的標籤 TODO 、Feature;為這個功能找到處理者;將其新增到對應的 看板

修改看板

【Vue 實踐】頁面生成 pdf 檔案-01

將所有的需求新增至 To do,再將要立即處理的移至 In progress

建立分支

【Vue 實踐】頁面生成 pdf 檔案-01

準備採用 Github Flow 的工作流,首先建立一個分支,在克隆到本地

git branch -av
# 建立本地分支並建立關聯
git checkout -b feature/download_pdf origin/feature/download_pdf 
複製程式碼

功能開發

安裝依賴

選取的是想法1,利用 canvas 來實現,安裝相關的依賴

npm i html2canvas -S
npm i jspdf -S
複製程式碼

註冊功能

這個功能將會被註冊為全域性的外掛進行呼叫,按照習慣,將其放入 plugins 資料夾下,引入依賴,註冊一套走起:

// 建立外掛 pdf.js
// 引入依賴
import Vue from "vue";
import html2canvas from "html2canvas";
import jspdf from "jspdf";

const PDF = {};
// eslint-disable-next-line no-unused-vars
PDF.install = function(Vue, options) {
  Vue.prototype.$pdf = function() {
    // eslint-disable-next-line no-console
    console.log("hello pdf");
  };
};

Vue.use(PDF);

export default PDF;


// 在 main.js 中註冊外掛
import "./plugins/pdf";

// 在對應的地方觸發方法
this.$pdf(); // hello world
複製程式碼

轉為 Canvas

首先需將 HTML 轉為 Canvas,看一下 html2canvas 是怎麼處理的:

【Vue 實踐】頁面生成 pdf 檔案-01

很簡單的語法,獲取 DOM 就可以了。

增加 ref 屬性

<share-page v-if="!shareLoading" ref="pdfPage"></share-page>
複製程式碼

將 DOM 傳遞到 觸發事件中

<script>
export default {
  methods: {
    download() { 
      this.$pdf(this.$refs.pdfPage.$el);
    }
  } 
}
</script>
複製程式碼

測試 DOM 結果

Vue.prototype.$pdf = function(dom) {
  // eslint-disable-next-line no-console
  console.log(dom); // 得到期望結果
};
複製程式碼

使用 html2canvas

Vue.prototype.$pdf = function(dom) {
  html2canvas(dom).then(canvas => {
    dom.appendChild(canvas);
  });
};
複製程式碼

前往頁面檢視,可以得到一個完美效果的 Canvas

列印為 PDF

接下來是處理成 pdf,看一下官網它是怎麼處理的:

【Vue 實踐】頁面生成 pdf 檔案-01

看起來很簡單,提供一張圖片(base64),然後就可以生成了。我們知道 canvas 是可以轉為 圖片(base64) 的,示例中給的圖片格式是 jpeg,所以 canvas 也處理為 jpeg

html2canvas(dom).then(canvas => {
  const jpeg = canvas.toDataURL("image/jpeg");
  const doc = new JsPDF();

  doc.setFontSize(40);
  doc.text(35, 25, "簡歷");
  doc.addImage(jpeg, "JPEG", 15, 40, 180, 160);
  doc.save("簡歷");
});
複製程式碼

好了,測試一下結果吧:

【Vue 實踐】頁面生成 pdf 檔案-01

簡歷是生成了,但是未免有些不對勁,看一下 文件 重新搞吧:

html2canvas(dom).then(canvas => {
  const [AWidth, AHeight] = [595.28, 841.89]; // a4
  const { width: CWidth, height: CHeight } = canvas;
  const PWidth = AWidth;
  const PHeight = (AWidth / CWidth) * CHeight;
  const jpeg = canvas.toDataURL("image/jpeg", 1.0);
  const doc = new JsPDF("", "pt", "a4");

  doc.addImage(jpeg, "JPEG", 0, 0, PWidth, PHeight);
  doc.save("簡歷");
});
複製程式碼

一頓操作發現簡歷長度超過 a4 紙的高度了,那就再給它增加一頁,此處 參考

Vue.prototype.$pdf = function(dom, user) {
html2canvas(dom).then(canvas => {
  const [AWidth, AHeight] = [595.28, 841.89]; // a4
  let position = 0;
  let { width: CWidth, height: CHeight } = canvas;
  const PWidth = AWidth;
  const PHeight = (AWidth / CWidth) * CHeight;
  const jpeg = canvas.toDataURL("image/jpeg", 1.0);
  const doc = new JsPDF("", "pt", "a4");

  if (CHeight < PHeight) {
    doc.addImage(jpeg, "JPEG", 0, 0, PWidth, PHeight);
  } else {
    while (CHeight > 0) {
      doc.addImage(jpeg, "JPEG", 0, position, PWidth, PHeight);
      CHeight -= PHeight;
      position -= AHeight;
      if (CHeight > 0) {
        doc.addPage();
      }
    }
  }
  doc.save(user);
});
複製程式碼

好了,大功告成,成功結果在介紹中展示了。

最後,提交,review,合併分支,釋出程式碼。

Bug

僅能算作勉強完成,分割時會導致連續的內容分開,這個感覺會耗時很久……

參考文件

  1. html2canvas
  2. jspdf
  3. toDataURL

相關文章