使用window.print()打印指定的一個(gè)vue 組件

在想打印一個(gè)web頁面的時(shí)候,會(huì)用到window.print()。默認(rèn)會(huì)打印當(dāng)前document內(nèi)容,樣式/圖片還有<body>里面的html標(biāo)簽.一般我們打印當(dāng)前頁面,不會(huì)是整個(gè)頁面,而只是打印當(dāng)前頁面部分內(nèi)容而已。一般是寫樣式,打印之前把不需要打印的標(biāo)簽通過display:none隱藏掉。
如果東西不多也可以這樣做,但是如果要打印其他頁面,還是得重新寫一下這樣的隱藏完了還得顯示回來,有點(diǎn)麻煩。這時(shí)候就想,能不能只打印一個(gè)組件這個(gè)組件里面的內(nèi)容都是我們要打印的東西。于是有了封裝一個(gè)打印組件的想法。

思路是這樣的,通過一個(gè)iframe 把當(dāng)前需要打印的組件內(nèi)容給到iframe的body,樣式呢,我們就拿當(dāng)前document里面的樣式。因?yàn)関ue組件用的也是當(dāng)前頁面的樣式,當(dāng)運(yùn)行npm run dev(npm run serve)的時(shí)候,css-loader /style-loader 會(huì)把組件的樣式打包到document的head標(biāo)簽下頁面。

所以就可以這樣寫 PrintView.vue

<template>
  <div class="print">
    <iframe id="iframe" style="display: none;"></iframe>
  </div>
</template>
<script>
export default {
  name: "print",
  props: {
    html: {
      type: String,
      default: ""
    }
  },
  watch: {
    html(val) {
      if (val) {
        this.setBodyHtml(val);
      }
    }
  },
  methods: {
    setBodyHtml(html) {
      const document = window.document;
      const iframe = window.frames[0];
      iframe.document.head.innerHTML = document.head.innerHTML; // 獲取當(dāng)前文檔的頭部給iframe
      iframe.document.body.innerHTML = html; // 把傳過來的html給iframe <body>

       //   打印
      iframe.window.print();
  }
};
</script>

組件中的iframe默認(rèn)不顯示的,因?yàn)椴恍枰吹剿?打印預(yù)覽有電腦的打印預(yù)覽.

然后通過props下的html這個(gè)屬性接收需要打印的組件的html.通過watch監(jiān)聽html的變化,當(dāng)有變化我們就調(diào)用自定義的
setBodyHtml方法打印,這個(gè)方法也很簡(jiǎn)單,把當(dāng)前頁面的頭部樣式給到當(dāng)前組件的iframe,把需要打印的html給
到當(dāng)前組件的iframe<body> 通過調(diào)用iframe.window.print();打印當(dāng)前組件。

window.print()打印效果

這樣會(huì)有一個(gè)問題,重新獲取到內(nèi)容的iframe,它自己需要重新加載css跟img,有時(shí)候會(huì)出現(xiàn)需要打印的組件樣式不對(duì)或者圖片不顯示的問題。所以在打印之前還需要監(jiān)聽下iframe加載的圖片跟樣式是否加載完成.

所以組件完整的寫法是這樣

<template>
  <div class="print">
    <iframe id="iframe" style="display: none;"></iframe>
  </div>
</template>
<script>
export default {
  name: "print",
  props: {
    html: {
      type: String,
      default: ""
    }
  },
  watch: {
    html(val) {
      if (val) {
        this.setBodyHtml(val);
      }
    }
  },
  methods: {
    setBodyHtml(html) {
      const document = window.document;
      const iframe = window.frames[0];
      iframe.document.head.innerHTML = document.head.innerHTML; // 獲取當(dāng)前文檔的頭部給iframe
      iframe.document.body.innerHTML = html; // 把傳過來的html給iframe頭部

      // 圖片和樣式加載完成
      Promise.all([this.loadStyle(), this.loadImage()]).then(res => {
        //   打印
        iframe.window.print();
      });
    },
    loadStyle() {
      const iframe = window.frames[0];
      const styles = iframe.document.head.getElementsByTagName("style"); // <style>
      const links = iframe.document.head.getElementsByTagName("link"); // <link>
      let arrs = [];
      arrs = arrs.concat(...styles, ...links);

      return new Promise((resolve, reject) => {
        for (let i = 0; i < arrs.length; i++) {
          arrs[i].onload = function() {
            if (i === arrs.length - 1) {
              console.log("style 樣式加載完成");
              resolve("style 樣式加載完成");
            }
          };
        }
      });
    },
    loadImage() {
      const iframe = window.frames[0];
      const imgs = iframe.document.body.getElementsByTagName("img"); // <img>
      
      return new Promise((resolve, reject) => {
        for (let i = 0; i < imgs.length; i++) {
          imgs[i].onload = function() {
            if (i === imgs.length - 1) {
              console.log("img 加載完成");
              resolve("img 加載完成");
            }
          };
        }
      });
    }
  }
};
</script>

通過loadStyle與loadImage這兩個(gè)方法,別找到iframe中的樣式和圖片. 樣式會(huì)有兩種,一種是head的<style>標(biāo)簽
打包生產(chǎn)的項(xiàng)目里,樣式是一個(gè)css文件,所以還需要找到<link>標(biāo)簽.通過Promise.all() 當(dāng)圖片和樣式onload完成后
就可以打印了.

用的時(shí)候 需要打印的頁面引入 PrintView組件

<print-view :html="printHtml" />

需要打印的組件打上ref屬性,例如ref="print",當(dāng)點(diǎn)擊打印按鈕的時(shí)候,

this.printHtml = this.$refs.printElement.innerHTML;

這樣就把需要打印的組件傳到我們打印組件的iframe,調(diào)出打印面板.


打印圖

至于打印成功不成功,只能通過肉眼判斷,因?yàn)槟氵@個(gè)電腦可能沒連打印機(jī)也是有可能的.


打印效果圖

要打印的這個(gè)圖呢,只是頁面上的一個(gè)組件,而不是完整的頁面。當(dāng)點(diǎn)擊打印按鈕,會(huì)彈出一個(gè)dialog,顯示出要打印的組件,然后指定打印的組件內(nèi)容。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容